新增完善测试模板
This commit is contained in:
5
tests/samples/README.md
Normal file
5
tests/samples/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# samples(样例,默认不执行)
|
||||
|
||||
本目录下的 ``*.py.sample`` **不会被** ``python tests/run_tests.py`` 收集。
|
||||
|
||||
复制为 ``tests/test_*.py``(去掉 ``.sample``)后,再按业务实现 service / golden 断言。
|
||||
37
tests/samples/test_golden_cases.py.sample
Normal file
37
tests/samples/test_golden_cases.py.sample
Normal file
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# 样例:复制为 ``tests/test_golden_cases.py`` 后运行;默认不收集。
|
||||
"""
|
||||
Golden fixture 回归(示意)。
|
||||
|
||||
- 从 ``tests/fixtures/`` 读取脱敏 JSON。
|
||||
- 调用 service 层(复制后替换为真实 import)。
|
||||
- 断言关键字段,而非全文 diff(外部系统常带时间戳/非确定性字段)。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import unittest
|
||||
|
||||
|
||||
def _fixtures_dir() -> str:
|
||||
return os.path.join(os.path.dirname(__file__), "..", "fixtures")
|
||||
|
||||
|
||||
class TestGoldenCasesSample(unittest.TestCase):
|
||||
def test_sample_request_matches_expected_shape(self) -> None:
|
||||
req_path = os.path.join(_fixtures_dir(), "sample_request.json")
|
||||
exp_path = os.path.join(_fixtures_dir(), "expected_response.json")
|
||||
with open(req_path, encoding="utf-8") as f:
|
||||
req = json.load(f)
|
||||
with open(exp_path, encoding="utf-8") as f:
|
||||
exp = json.load(f)
|
||||
self.assertEqual(req["request_id"], "req_test_001")
|
||||
self.assertTrue(req["parameters"]["options"]["dry_run"])
|
||||
# 示意:out = run(req); 然后 assert out["success"] == exp["success"] 等关键字段
|
||||
self.assertTrue(exp["success"])
|
||||
self.assertEqual(exp["data"]["status"], "ok")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
46
tests/samples/test_service_contract.py.sample
Normal file
46
tests/samples/test_service_contract.py.sample
Normal file
@@ -0,0 +1,46 @@
|
||||
# -*- 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()
|
||||
Reference in New Issue
Block a user