Files
cmautobuy/client/test/test_pdd_page_classifier.py
T

142 lines
5.1 KiB
Python

"""PDD 页面分类与商品深链状态机测试。"""
from pathlib import Path
import unittest
import xml.etree.ElementTree as ET
from src.pdd_page_classifier import (
ACTION_NETWORK_ERROR,
ACTION_OUT_OF_STOCK,
ACTION_READY,
ACTION_REFRESH,
ACTION_REOPEN,
ACTION_UNAVAILABLE,
ACTION_WAIT,
PAGE_CAPTCHA,
PAGE_EXTERNAL,
PAGE_GOODS,
PAGE_HOME,
PAGE_LOADING,
PAGE_LOGIN_REQUIRED,
PAGE_NETWORK_ERROR,
PAGE_OUT_OF_STOCK,
PAGE_RISK_CONTROL,
GoodsOpenTracker,
classify_pdd_page,
)
FIXTURES = Path(__file__).parent / "fixtures"
PDD = "com.xunmeng.pinduoduo"
def observation(text: str, package: str = PDD):
xml = (
'<hierarchy><node package="{0}" class="android.widget.TextView" '
'text="{1}" bounds="[0,0][900,300]" visible-to-user="true"/>'
'<node package="{0}" text="占位一"/><node package="{0}" '
'text="占位二"/></hierarchy>'
).format(package, text)
return classify_pdd_page(ET.fromstring(xml), package)
class PddPageClassifierTest(unittest.TestCase):
def test_real_home_fixture_ignores_incorrect_focused_package(self) -> None:
root = ET.parse(FIXTURES / "pdd_home_page.xml").getroot()
result = classify_pdd_page(root, "com.android.settings")
self.assertEqual(PAGE_HOME, result.kind)
self.assertTrue(result.pdd_hierarchy)
def test_special_pages_are_not_home(self) -> None:
cases = {
"加载中": PAGE_LOADING,
"网络不给力": PAGE_NETWORK_ERROR,
"手机号登录": PAGE_LOGIN_REQUIRED,
"请完成验证": PAGE_CAPTCHA,
"操作频繁": PAGE_RISK_CONTROL,
"立即购买": PAGE_GOODS,
"商品已售罄,推荐以下相似商品": PAGE_OUT_OF_STOCK,
}
for label, expected in cases.items():
with self.subTest(label=label):
self.assertEqual(expected, observation(label).kind)
def test_browser_word_does_not_count_as_goods(self) -> None:
result = observation("立即购买", "com.android.chrome")
self.assertEqual(PAGE_EXTERNAL, result.kind)
def test_transient_home_can_reach_goods_without_reopen(self) -> None:
home = classify_pdd_page(
ET.parse(FIXTURES / "pdd_home_page.xml").getroot(), PDD
)
tracker = GoodsOpenTracker(None, 0.0)
self.assertEqual(ACTION_WAIT, tracker.observe(home, 2.0).action)
self.assertEqual(ACTION_WAIT, tracker.observe(home, 2.1).action)
self.assertEqual(
ACTION_READY, tracker.observe(observation("立即购买"), 2.2).action
)
def test_stable_home_reopens_once_then_marks_unavailable(self) -> None:
home = classify_pdd_page(
ET.parse(FIXTURES / "pdd_home_page.xml").getroot(), PDD
)
tracker = GoodsOpenTracker(None, 0.0)
for at in (2.0, 2.1):
self.assertEqual(ACTION_WAIT, tracker.observe(home, at).action)
self.assertEqual(ACTION_REOPEN, tracker.observe(home, 2.2).action)
tracker.reopened(3.0)
for at in (5.0, 5.1):
self.assertEqual(ACTION_WAIT, tracker.observe(home, at).action)
self.assertEqual(ACTION_UNAVAILABLE, tracker.observe(home, 5.2).action)
def test_old_goods_tree_is_not_accepted_as_new_target(self) -> None:
old = observation("旧商品标题 立即购买")
tracker = GoodsOpenTracker(old, 0.0)
self.assertEqual(ACTION_WAIT, tracker.observe(old, 0.2).action)
self.assertTrue(tracker.stale_goods_seen)
new = observation("目标商品标题 立即购买")
self.assertEqual(ACTION_READY, tracker.observe(new, 0.3).action)
def test_network_error_has_own_decision(self) -> None:
tracker = GoodsOpenTracker(None, 0.0)
decision = tracker.observe(observation("网络不给力"), 3.0)
self.assertEqual(ACTION_NETWORK_ERROR, decision.action)
def test_sold_out_page_refreshes_once_then_can_recover(self) -> None:
tracker = GoodsOpenTracker(None, 0.0)
sold_out = observation("商品已售罄,推荐以下相似商品")
self.assertEqual(ACTION_REFRESH, tracker.observe(sold_out, 0.2).action)
tracker.refreshed_out_of_stock(0.3)
self.assertTrue(tracker.out_of_stock_refreshed)
self.assertEqual(
ACTION_READY,
tracker.observe(observation("目标商品 立即购买"), 0.8).action,
)
def test_sold_out_after_refresh_is_unavailable_without_second_refresh(self) -> None:
tracker = GoodsOpenTracker(None, 0.0)
sold_out = observation("该商品已售罄")
self.assertEqual(ACTION_REFRESH, tracker.observe(sold_out, 0.2).action)
tracker.refreshed_out_of_stock(0.3)
self.assertEqual(
ACTION_OUT_OF_STOCK,
tracker.observe(sold_out, 0.8).action,
)
with self.assertRaises(RuntimeError):
tracker.refreshed_out_of_stock(0.9)
def test_sku_sold_out_text_is_still_a_normal_goods_page(self) -> None:
result = observation("立即购买 尺码 L(售罄)")
self.assertEqual(PAGE_GOODS, result.kind)
if __name__ == "__main__":
unittest.main()