继续完善测试模板

This commit is contained in:
2026-05-03 18:08:57 +08:00
parent dd6236866e
commit 4730cd527d
5 changed files with 184 additions and 3 deletions

View File

@@ -6,6 +6,43 @@
--- ---
## 我该把测试写在哪里?
人类开发者与 Cursor 等 AI 工具在加用例前,先对照下表决定**文件落点**与**是否默认执行**
| 场景 | 放在哪里 | 默认是否运行 | 说明 |
|------|----------|--------------|------|
| CLI / health / version / metadata / runtime 路径 | `tests/test_*.py` | 是 | 默认必跑,保持轻量、无外联 |
| 纯函数 / 业务规则 | `tests/test_*.py` | 是 | 不依赖真实外部系统 |
| service 层契约 | 从 `tests/samples/test_service_contract.py.sample` 复制到 `tests/test_service_contract.py` | 是,复制后 | 用 `FakeAdapter` / stub 注入外部依赖 |
| golden fixture 回归 | 从 `tests/samples/test_golden_cases.py.sample` 复制到 `tests/test_golden_cases.py` | 是,复制后 | 输入样例 + 期望输出,适合解析、计算、校验类技能 |
| 仿真 API | `tests/integration/test_simulator_api_contract.py.sample` | 否 | 复制并设置 `OPENCLAW_TEST_TARGET=simulator_api`(或兼容键名 `OPENCLOW_TEST_TARGET`)后按需运行 |
| 仿真 RPA / 页面操作 | `tests/integration/test_simulator_rpa_contract.py.sample` | 否 | 用 localhost / 仿真页面,不碰真实系统 |
| 真实 API | `tests/integration/test_real_api_contract.py.sample` | 否 | 必须 `OPENCLAW_TEST_TARGET=real_api` 且 `ALLOW_REAL_API=1` |
| 真实 RPA | `tests/integration/test_real_rpa_contract.py.sample` | 否 | 最高风险,只能手动触发 |
| 桌面宿主 E2E | `tests/desktop/test_desktop_smoke.py.sample` | 否 | 需要 pytest + `jiangchang_desktop_sdk` |
说明:`python tests/run_tests.py` **只**收集 `tests/` **根目录**下的 `test_*.py`;子目录里的 `*.sample` 与 desktop 用例**不会**被默认发现。
---
## 新技能最小测试清单
从本模板复制出新技能仓库后,建议至少逐项确认:
- [ ] `python tests/run_tests.py -v` 能通过。
- [ ] `python scripts/main.py health` 能通过。
- [ ] `python scripts/main.py version` 输出 JSON且 `skill` 与目录名 / `SKILL.md` / `constants.SKILL_SLUG` 一致。
- [ ] 所有 DB / 文件写入都在 `IsolatedDataRoot`(或等价隔离)下测试,不写真实数据目录。
- [ ] 外部系统默认使用 mock / `FakeAdapter`,不访问真实 API不打开真实 RPA。
- [ ] 至少有 1 个成功路径测试。
- [ ] 至少有 1 个缺必填字段 / 非法输入测试。
- [ ] 如果有 adapter至少覆盖 timeout / unauthorized / invalid response可用 fake 模拟)。
- [ ] 如果有解析 / 计算 / 校验类业务,至少保留 1 组 golden fixture脱敏
- [ ] 真实 API / 真实 RPA 测试只放 `tests/integration/`,并且默认 `.sample`,不默认运行。
---
## 1. 默认必跑unittest ## 1. 默认必跑unittest
在**技能仓库根目录**执行: 在**技能仓库根目录**执行:
@@ -113,6 +150,21 @@ python tests/run_tests.py test_cli_smoke
--- ---
## AI 编程工具注意事项Cursor 等)
以下约束适用于为本仓库或复制出的技能编写/修改测试时,**避免误伤业务与生产**
- **不要为了**让测试通过去改业务代码,除非用户明确要求修改实现。
- **不要**把真实外部系统调用写进默认的 `tests/test_*.py`(默认套件须无外联、无真实浏览器)。
- **不要**把 `*.sample` 改名为可执行测试或移入根目录并去掉 `.sample`,除非用户明确要求启用 integration / 真实联调。
- **不要**硬编码真实凭证、token、cookie、生产 URL占位请用明显虚构域名如 `example.invalid`)或文档约定的 `credential_ref`。
- 默认测试只能使用 **mock、stub、`FakeAdapter`、fixtures、隔离 SQLite** 等安全手段。
- 业务逻辑应优先在 **service 层** 编写与测试,不要只断言 CLI 文案。
- 异常路径应返回**结构化错误**(如统一错误码/字段),避免裸异常直接穿透到 CLI。
- 有真实系统联调需求时,测试应写在 `tests/integration/`,并配合 `OPENCLAW_TEST_TARGET` / `ALLOW_REAL_*` / `ALLOW_WRITE_ACTIONS` 等**显式开关**;不得默认开启。
---
## 6. 与 content-manager 的关系 ## 6. 与 content-manager 的关系
- **未**复制 article / media / prompt / NotebookLM 等业务测试。 - **未**复制 article / media / prompt / NotebookLM 等业务测试。

View File

@@ -30,3 +30,5 @@ pytest tests/desktop/test_desktop_smoke.py -v -s
- **后端 / CLI / DB**:请使用仓库根目录下 `python tests/run_tests.py`(见 `tests/README.md`)。 - **后端 / CLI / DB**:请使用仓库根目录下 `python tests/run_tests.py`(见 `tests/README.md`)。
- **桌面 E2E**:仅在本目录用 **pytest** 维护,二者互补、互不替代。 - **桌面 E2E**:仅在本目录用 **pytest** 维护,二者互补、互不替代。
若仅需验证 **service 业务逻辑**、契约与 golden 回归,**不要**写 desktop E2Edesktop 只用于验证**宿主 UI、路由、`jiangchang://` 协议、真实用户交互链路**等与桌面宿主强相关的行为。

View File

@@ -15,3 +15,13 @@
| `sample_request.json` | 通用请求体样例,供 ``tests/samples/test_golden_cases.py.sample`` 演示读取。 | | `sample_request.json` | 通用请求体样例,供 ``tests/samples/test_golden_cases.py.sample`` 演示读取。 |
| `expected_response.json` | 与上配套的期望摘要字段(业务复制后按域替换)。 | | `expected_response.json` | 与上配套的期望摘要字段(业务复制后按域替换)。 |
| `adapter_profiles.sample.yaml` | 五类运行方式mock / simulator_api / simulator_rpa / real_api / real_rpa的配置表达样例。 | | `adapter_profiles.sample.yaml` | 五类运行方式mock / simulator_api / simulator_rpa / real_api / real_rpa的配置表达样例。 |
---
## 给 AI 工具的替换规则
- 可以按业务**重命名字段**、增减键名,但必须保持**虚构、脱敏**;不得把真实客户标识原样搬进仓库。
- 可以**新增**更多 fixture 文件,例如 `case_valid_001.json`、`case_missing_required_001.json`,并在测试中通过相对路径读取。
- **禁止**将真实企业数据、真实单证截图中的文字、真实报关要素未经处理直接复制进 `fixtures/`。
- 若用例来自真实客户样本,须先**脱敏、泛化、替换编号与地名**,再作为模板数据提交。

View File

@@ -5,6 +5,16 @@
- ``python tests/run_tests.py`` 只收集 ``tests/`` 根目录下 ``test_*.py``**不会**进入本目录。 - ``python tests/run_tests.py`` 只收集 ``tests/`` 根目录下 ``test_*.py``**不会**进入本目录。
- 本目录下文件一律为 ``*.py.sample``pytest / unittest **默认也不会**按普通 ``test_*.py`` 收集。 - 本目录下文件一律为 ``*.py.sample``pytest / unittest **默认也不会**按普通 ``test_*.py`` 收集。
## 与 samples 的区别
| 维度 | `tests/samples/` | `tests/integration/` |
|------|------------------|------------------------|
| 目的 | 默认可**升级**为根目录 `test_*.py`**业务单元 / service 契约 / golden** 范式 | **外联联调**范式:网络、浏览器、仿真或真实系统 |
| 默认执行 | `.sample` 不执行;复制到根目录并改名后才进入默认套件 | **永远不**作为默认 unittest 的一部分;复制后仍需显式环境变量与手动/CI 任务触发 |
| 典型内容 | `FakeAdapter`、fixture、隔离 DB | `localhost` 仿真、真实 API授权、真实 RPA最高风险 |
**原则**:只要会访问**网络**、**浏览器**、**真实或仿真外部系统**,应优先放在 `integration`(并保持 `.sample` 直至团队同意启用),而不是写进默认 `tests/test_*.py`
## 何时使用 ## 何时使用
| 场景 | 建议 ``OPENCLAW_TEST_TARGET`` | 其它条件 | | 场景 | 建议 ``OPENCLAW_TEST_TARGET`` | 其它条件 |

View File

@@ -1,5 +1,112 @@
# samples样例默认不执行 # samples业务测试样例,默认不执行)
本目录下的 ``*.py.sample`` **不会被** ``python tests/run_tests.py`` 收集 本目录存放**可复制到根目录的业务测试范式**,面向「企业数字员工技能」中 **ERP、TMS、WMS、船司、报关、邮件、LLM、RPA** 等外联场景下的 **service / golden** 测法说明
复制为 ``tests/test_*.py``(去掉 ``.sample``)后,再按业务实现 service / golden 断言。 ---
## 作用
- 这里的文件是 **`.py.sample`**`python tests/run_tests.py` **不会**收集本目录(`run_tests.py` 只发现 `tests/` 根目录下的 `test_*.py`)。
- 人类或 AI 需要启用范式时:**复制**到 `tests/test_<名称>.py`(去掉 `.sample`),再按业务改 import、断言与 fixture 路径。
- **禁止**把真实联调、真实网络、真实 RPA 写进复制后的默认用例;此类内容应放在 `tests/integration/*.sample` 并配合环境变量开关。
---
## 两类样例文件
### 1. `test_service_contract.py.sample`
**适合:**
- 技能有清晰的 **service 层入口**,例如 `run(...)``handle(...)``execute(...)`
- 需要验证:**成功路径**、**参数/校验错误**、**adapter 异常被转换为业务可读错误**。
- 需要用 **`FakeAdapter`**(见 `tests/adapter_test_utils.py`)或自建 **stub** 替代 ERP、TMS、WMS、船司、报关、LLM、RPA 等,**不**发真实 HTTP、**不**开真实浏览器。
### 2. `test_golden_cases.py.sample`
**适合:**
- **解析类**:邮件/单证/PDF/Excel 等结构化输出。
- **计算类**:费用、税费、分摊、账单字段。
- **校验类**:合规、字段一致性、状态机规则。
推荐配合根目录下的 **`tests/fixtures/sample_request.json`** 与 **`tests/fixtures/expected_response.json`**(复制技能后按域替换字段,保持脱敏)。
---
## 如何启用 service contract 样例
1. **复制文件**
`tests/samples/test_service_contract.py.sample`
`tests/test_service_contract.py`(或 `tests/test_<domain>_service_contract.py`,须符合根目录 `test_*.py` 命名以便 `run_tests.py` 收集)。
2. **替换示例 import**
把注释中的示意:
`# from service.your_service import run`
改为真实模块,例如:
`from service.quote_service import run_quote`
(具体路径以技能代码为准。)
3. **注入假外部依赖**
- **不要**在默认用例里直接 `requests` 访问 ERP/TMS/WMS 等。
- **不要**打开真实网页或驱动真实 RPA。
- **不要**调用真实 LLM可 stub 返回固定 JSON。
-**timeout / unauthorized / invalid_response** 等分支,用 `FakeAdapter` 或自建 fake 模拟(与 `adapter_test_utils` 思路一致)。
4. **至少保留三类断言习惯**
- **成功路径**:返回 `success: true` 或与技能约定的成功结构。
- **参数错误**:缺必填字段时返回**结构化** error字段/码),而非未捕获裸异常。
- **外部异常**adapter 超时、鉴权失败、脏响应等被转换为**可读、可重试标识明确**的错误形态(按产品约定)。
5. **给 AI 的提示**
复制后全文搜索 `your_service``TODO``伪代码` 等占位符并替换;不要留下指向真实客户的示例数据。
---
## 如何启用 golden case 样例
1. **复制文件**
`tests/samples/test_golden_cases.py.sample`
`tests/test_golden_cases.py`(或 `tests/test_<domain>_golden.py`)。
2. **按业务修改 fixtures**(仍须脱敏)
- `tests/fixtures/sample_request.json`:请求或输入快照。
- `tests/fixtures/expected_response.json`:期望摘要或关键字段。
可新增多组文件,如 `case_valid_001.json`,并在测试中显式读取路径。
3. **断言建议(避免脆弱用例)**
- 比较**关键字段**,避免对整段 JSON 做机械全文 diff。
- **忽略**时间戳、随机 id、`trace_id` 等非确定字段。
- 对列表:断言**长度**、**关键元素**、**排序规则**(若业务保证顺序)。
- 对金额/数量:断言 Decimal 字符串、或允许文档约定的小范围误差。
4. **与 service 的关系**
golden 用例仍应通过 **service 层**(或纯函数)得到输出,再与 fixture 对比,而不是从 CLI 字符串 scrape。
---
## 不应该写在 samples 复制件里的内容
以下若出现,应移到 **`tests/integration/*.sample`** 或 **`tests/desktop/*.sample`**,并加环境变量授权说明:
- 访问**真实** API 或内网服务。
- 打开**真实** RPA 页面或生产门户。
- 读取**真实**客户文件、生产数据库。
- 在测试中写入**真实**数据根或共享盘。
- 任何真实 **token / cookie / 密码** 字面量。
- 耗时极长、强依赖宿主 UI 抖动、无法在 CI 稳定复现的用例(不要塞进默认 `tests/test_*.py`)。
---
## 推荐命名(复制到根目录后)
| 用途 | 示例文件名 |
|------|------------|
| Service 契约 | `tests/test_service_contract.py` |
| Golden / fixture 回归 | `tests/test_golden_cases.py` |
| 领域规则 | `tests/test_<domain>_rules.py` |
| 校验逻辑 | `tests/test_<domain>_validation.py` |
命名需满足:`tests/` 根目录下 `test_*.py`,以便 `python tests/run_tests.py` 默认发现。
更多分层说明见 **`tests/README.md`**(「我该把测试写在哪里?」与「新技能最小测试清单」)。