# -*- coding: utf-8 -*- # 本文件为样例:复制到 ``tests/test_service_contract.py``(或业务仓 tests 根)后按实际 service 改名运行。 # 默认 **不会** 被 ``python tests/run_tests.py`` 收集(扩展名为 .sample)。 """ Service 层契约测试范式(示意)。 复制为真实技能后: 1. 将 ``from service.your_service import run`` 替换为实际模块与入口函数。 2. 用 ``FakeAdapter`` / 内存 stub 替代真实 ERP/TMS/WMS 等外呼。 3. 需要真实外网或真实 RPA 时,勿在本文件直接写死凭证;改用 ``tests/integration/*.sample`` + 环境开关。 """ from __future__ import annotations import unittest from adapter_test_utils import FakeAdapter # from service.your_service import run # noqa: ERA001 — 复制后取消注释并实现 class TestServiceContractSample(unittest.TestCase): """三类常见契约:成功路径、结构化错误、上游超时转可重试错误。""" def test_success_path_returns_success_true(self) -> None: # 示意:run(payload, adapter=FakeAdapter("success")) -> {"success": True, ...} ad = FakeAdapter("success") out = ad.call({"op": "ping"}) self.assertTrue(out.get("success")) def test_missing_required_field_returns_structured_error_not_bare_exception(self) -> None: # 示意:业务层应对必填字段做校验,返回 {"success": False, "error": {"code": "...", "message": "..."}} err = {"success": False, "error": {"code": "VALIDATION", "message": "missing shipment_id"}} self.assertFalse(err["success"]) self.assertIn("code", err["error"]) def test_adapter_timeout_maps_to_retriable_error(self) -> None: # 示意:捕获 TimeoutError 后映射为业务可重试错误码,而不是让裸异常穿透 CLI ad = FakeAdapter("timeout") with self.assertRaises(TimeoutError): ad.call({}) # 真实实现中:except TimeoutError: return {"success": False, "error": {"code": "UPSTREAM_TIMEOUT", "retriable": True}} if __name__ == "__main__": unittest.main()