- Split framework into core/ (config, logger, db, driver factories, screenshot, allure integration) and pages/ (PO layer: base/admin/driver); flatten test files per platform (web/admin, app/driver_android, cross_end) - Slim root conftest.py 656 -> ~100 lines: drop inline CN HTML report, add Allure severity mapping (p0/p1/p2 -> blocker/normal/minor) and environment.properties; support both tests.*-prefixed and bare imports - Preserve TC-D2S-001/002 cross-end E2E cases with business logic unchanged, add allure epic/feature/story/step annotations - Deduplicate: single makereport hook, shared failure-screenshot helpers, single SCREENSHOTS_DIR constant; deterministic auth-state role loading - Move DB credentials from db_helper.py into test_config.yaml (database section) - Move pytest.ini to repo root; switch reporting to allure-pytest (drop pytest-html/junitxml); update requirements.txt accordingly - Delete deprecated scaffolding: test_freight_full_flow + 6 stale page objects, iOS/shipper empty shells, dead utils - Fix flaky vxe-table action-row wait: wait for a visible td instead of hidden placeholder rows (fixed shipper-payment timeouts) - Verified end-to-end against live env: both E2E cases pass (2 passed 3m12s); run artifacts (logs/screenshots/allure) included per repo convention
103 lines
4.1 KiB
Python
103 lines
4.1 KiB
Python
"""全局 conftest — 配置/日志 fixtures + Allure 集成。
|
||
|
||
架构分层 (POM):
|
||
core/ 框架层: 配置、日志、DB、驱动工厂、截图、Allure 集成
|
||
pages/ PO 层: 页面对象,与用例分离
|
||
config/ YAML 配置
|
||
|
||
Usage:
|
||
def test_xxx(admin_config): # 管理端配置
|
||
def test_xxx(driver_android_config): # 司机安卓配置
|
||
"""
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import allure
|
||
import pytest
|
||
|
||
# 兼容两种 import 风格: from tests.core.xxx (项目根为源根)
|
||
# 与 from core.xxx (tests/ 为源根, 如 PyCharm 将 tests/ 标记为 Sources Root)
|
||
if (tests_root := str(Path(__file__).parent)) not in sys.path:
|
||
sys.path.insert(0, tests_root)
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def config():
|
||
"""全局配置(session 级,只加载一次)。"""
|
||
from tests.core.config_loader import load_config
|
||
return load_config()
|
||
|
||
|
||
@pytest.fixture(scope="function")
|
||
def logger(request):
|
||
"""每个测试函数的 logger。"""
|
||
from tests.core.logger import get_logger
|
||
module_name = request.module.__name__.replace("tests.", "")
|
||
return get_logger(module_name)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
# 各端配置 fixture(从 config 中摘取对应 section)
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
|
||
@pytest.fixture(scope="session")
|
||
def admin_config(config):
|
||
"""管理端 (Playwright) 配置。"""
|
||
return config["admin"]
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def mini_program_config(config):
|
||
"""司机端小程序 (miniprogram-automator) 配置。"""
|
||
return config["mini_program"]
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def driver_android_config(config):
|
||
"""司机安卓端 (Appium) 配置。"""
|
||
return config["driver_android"]
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
# Allure 集成
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
|
||
# pytest marker → Allure severity 自动映射(marker 是唯一事实源)
|
||
_MARKER_SEVERITY = {
|
||
"p0": allure.severity_level.BLOCKER,
|
||
"p1": allure.severity_level.NORMAL,
|
||
"p2": allure.severity_level.MINOR,
|
||
}
|
||
|
||
|
||
def pytest_collection_modifyitems(items):
|
||
"""按 p0/p1/p2 marker 自动设置 Allure severity。"""
|
||
for item in items:
|
||
for marker, severity in _MARKER_SEVERITY.items():
|
||
if item.get_closest_marker(marker):
|
||
item.add_marker(allure.severity(severity))
|
||
break
|
||
|
||
|
||
def pytest_sessionfinish(session):
|
||
"""向 allure-results 写入 environment.properties。"""
|
||
# 注意: allure-pytest 的 --alluredir 选项 dest 为 allure_report_dir
|
||
results_dir = session.config.getoption("allure_report_dir", default=None)
|
||
if not results_dir:
|
||
return
|
||
from tests.core.allure_support import write_environment_properties
|
||
from tests.core.config_loader import load_config
|
||
write_environment_properties(results_dir, load_config())
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
# Report hook — 让 request.node.rep_call.failed 可用于失败截图
|
||
# ═══════════════════════════════════════════════════════════════════
|
||
|
||
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
||
def pytest_runtest_makereport(item, call):
|
||
outcome = yield
|
||
rep = outcome.get_result()
|
||
setattr(item, f"rep_{rep.when}", rep)
|