Files
Yb-QaAutomationHub/tests/api/test_yun8_transport_flow.py
T
xst 52b73f456c refactor(api): yun8_sync 并入 tests 分层框架(接口层 apis/yun8 + 用例层 api + Allure)
- tests/core: 新增 BaseHttpClient 统一 HTTP 封装(直连绕行/超时/日志/自定义编码);
  db_helper 追加 Db 长连接类(事务/mogrify/自动重连),既有函数不动
- tests/apis/yun8: 21 个 step 方法按域拆分为 5 个 Mixin(driver/accounting/
  audit_payment/receipt/third_party),Yun8Pipeline 24 步编排原样迁移,
  SQL 全部参数化并集中至 sql_templates
- tests/api: 5 阶段有序 P0 E2E 用例(业务失败由 print 改为真实报错)+
  README 迁移(删除明文密码段,修正步骤编号漂移)
- yun8_sync 目录退役:配置并入 test_config.yaml 的 yun8_api 段;
  造数 CLI 保留(python -m tests.apis.yun8.cli,兼容旧 config.yaml 结构)
- pytest.ini 注册 api/yun8_sync marker;requirements.txt 补 requests>=2.28
- 静态验证: compileall / 全仓 collect 24 条 / marker 过滤 / CLI --help /
  客户端与 pipeline 离线实例化 / SQL 占位符核对 / cross_end 兼容
2026-09-08 11:38:17 +08:00

115 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""yun8 运输流程 API 造数 — 24 步全链路 E2E。
⚠️ 此套件会真实调用测试环境接口并写入数据库(造运单/打款/回单/ETC 发票),
不属于默认冒烟扫描范围,请显式按 marker 运行:
pytest tests/api -m yun8_sync -v
5 个阶段用例按定义顺序执行(同一类内定义序即执行序,勿并行),
共享一套 Yun8Pipeline(Postman Collection Variables 上下文):
阶段 A driver → 阶段 B accounting → 阶段 C audit_payment
→ 阶段 D receipt → 阶段 E etc
前置阶段失败时,后续阶段自动 skip(与 CLI 一次循环失败即中止语义一致)。
Usage:
pytest tests/api/test_yun8_transport_flow.py -v
"""
import allure
import pytest
pytestmark = [pytest.mark.api, pytest.mark.yun8_sync, pytest.mark.p0]
@allure.epic("运八网络货运平台")
@allure.feature("yun8 运输流程 API 造数 — 24 步全链路")
class TestYun8TransportFlow:
"""运输流程全链路:接口驱动 + SQL 造数(详见 tests/api/README.md)。"""
# ── 中断守卫:前置阶段失败则跳过 ──────────────────────────────
def _guard(self, yun8_context: dict):
if yun8_context["aborted"]:
pytest.skip(f"前置阶段失败: {yun8_context['aborted']}")
def _run(self, yun8_context: dict, stage: str, fn, *args, **kwargs):
"""执行编排方法,失败时记录中断原因后原样抛出。"""
try:
return fn(*args, **kwargs)
except Exception as exc:
yun8_context["aborted"] = f"{stage}: {exc}"
raise
@staticmethod
def _execute_after_audit(yun8_pipeline) -> bool:
return yun8_pipeline.config.get("accounting", {}).get(
"execute_after_audit", True)
# ═══════════════════════════════════════════════════════════════
# 阶段 A-E
# ═══════════════════════════════════════════════════════════════
@allure.story("阶段A — 司机端 (Step 01-05)")
@allure.title("TC-Y8-001 司机端 查询货源→接单→装货→卸货")
def test_stage_a_driver_flow(self, yun8_pipeline, yun8_context):
"""查询货源→接单→查询待运输单→装货→卸货,产出 code/orderCode。"""
self._guard(yun8_context)
with allure.step("执行司机端流程 run_driver_flow (Step 01-05)"):
vars_ = self._run(yun8_context, "阶段A",
yun8_pipeline.run_driver_flow)
assert vars_.get("mainOrderCode"), "mainOrderCode 为空"
assert vars_.get("code"), "待运输单 code 为空"
assert vars_.get("orderCode"), "orderCode 为空"
@allure.story("阶段B — 运费核算 (Step 06-09)")
@allure.title("TC-Y8-002 核算查询→详情→试算→提交")
def test_stage_b_accounting_flow(self, yun8_pipeline, yun8_context):
"""查询运单→运单详情→核算试算→核算提交,产出 30+ 核算字段。"""
self._guard(yun8_context)
with allure.step("执行运费核算流程 run_accounting_flow (Step 06-09)"):
vars_ = self._run(yun8_context, "阶段B",
yun8_pipeline.run_accounting_flow)
assert vars_.get("deliveryCashFee") != "", "deliveryCashFee 为空"
assert vars_.get("shipmentActualCash") != "", "shipmentActualCash 为空"
@allure.story("阶段C — 审核 & 付款 (Step 10-16)")
@allure.title("TC-Y8-003 审核通过→油卡充值→司机打款→货主打款")
def test_stage_c_audit_payment_flow(self, yun8_pipeline, yun8_context):
"""查询审核→审核通过→(分账)→油卡充值→财务打款→货主打款。
成功判定 = 编排全程无 Yun8StepError / HTTP 异常。
execute_after_audit=false 时编排内部自行跳过 12-16 步。
"""
self._guard(yun8_context)
with allure.step("执行审核付款流程 run_audit_payment_flow (Step 10-16)"):
self._run(yun8_context, "阶段C",
yun8_pipeline.run_audit_payment_flow)
@allure.story("阶段D — 回单文件 + SQL (Step 17-21)")
@allure.title("TC-Y8-004 提取payNo→回单INSERT→上报运单")
def test_stage_d_receipt_flow(self, yun8_pipeline, yun8_context):
"""payNo 提取→打款记录分页→文件名前缀→回单 INSERT→上报运单。"""
self._guard(yun8_context)
if not self._execute_after_audit(yun8_pipeline):
pytest.skip("execute_after_audit=false,receipt 阶段被配置跳过")
with allure.step("执行回单文件流程 run_receipt_file_flow (Step 17-21)"):
results = self._run(yun8_context, "阶段D",
yun8_pipeline.run_receipt_file_flow,
dry_run=False)
assert yun8_pipeline.vars.get("payNo"), "payNo 为空"
assert results, "无任何打款记录可处理(remit_records 为空)"
inserted = [r for r in results if r.get("status") == "inserted"]
assert inserted, f"没有成功插入的回单记录: {results}"
@allure.story("阶段E — ETC 开票 SQL (Step 22-24)")
@allure.title("TC-Y8-005 ETC发票INSERT→推送记录INSERT→开票状态更新")
def test_stage_e_etc_invoice_flow(self, yun8_pipeline, yun8_context):
"""写入 base_etc_invoice × N → tms_order_etc_push → 更新开票状态。"""
self._guard(yun8_context)
if not self._execute_after_audit(yun8_pipeline):
pytest.skip("execute_after_audit=false,ETC 阶段被配置跳过")
with allure.step("执行 ETC 开票流程 run_etc_invoice_flow (Step 22-24)"):
results = self._run(yun8_context, "阶段E",
yun8_pipeline.run_etc_invoice_flow,
dry_run=False)
errors = [r for r in results if r.get("status") == "error"]
assert not errors, f"ETC SQL 写入存在失败项: {errors}"