# Test Design

> 基于测试知识库和测试规范，为指定模块或需求 suite 生成 Markdown 用例和 mismatch 记录

- Skill: `tlzmw001/test-design` (Agent Skill)
- Install (CLI): `npx skillmds@latest add tlzmw001/test-design`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tlzmw001/test-design/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: tlzmw001 (https://skillmd.com/u/tlzmw001)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tlzmw001/test-design

---


# 测试用例设计

为 `$target` 下的 `$module` 模块，或某个 L2 需求 suite 生成 Markdown 测试用例。

输出目录：`$suite_dir`。优先使用 `test_workspace/suites/{target}/{suite}/` 或用户指定的任意 suite 目录，并在后续 `test-scaffold` / `test-codegen` 中由 `suite.yaml` 绑定 target/module。

## 前置：读取项目配置

优先读 `aitest_config/aitest.yaml`，获取：
- `workspace.paths.*` — 知识库、用例、suite、文档等目录路径
- `targets.registry` / `modules.registry` — 已登记 target/module 的位置
- `codegen.*` — 模块缩写、断言规则、默认请求字段等 codegen 约束

读取 `aitest_config/aitest.yaml` 获取 workspace 路径、codegen 默认规则和 target/module registry 配置。

读取 `test_workspace/targets/{target}/target.yaml`（存在时），获取公开接口、route/schema 搜索模式、默认 generated/reports 目录等 target 级信息。

## 执行流程

### 第一步：读取规范和上下文

1. 读 `{paths.test_spec}`（TEST_SPEC），建立：
   - 编号规则和模块缩写对照表
   - 优先级定义（P0/P1/P2）
   - 质量红线（Q1-Q10）
   - 排除场景列表（生成时跳过）
   - 关注场景列表（生成时必须覆盖）
   - 已知陷阱列表（生成时逐条自检，避免重犯已知错误模式）

   **硬约束**：在模块缩写对照表中查找 `$module` 对应的缩写。如果该模块未在表中登记，**停止执行**，提示用户先在 TEST_SPEC 的"模块缩写对照表"中补登记，避免编号冲突。同一 workspace 存在多个 target 时，仍以 `$target/$module` 作为定位范围。

2. 读 `{paths.l0_architecture}`（L0），从模块索引表中找到 `$module` 对应的：
   - L1 文档路径
   - 关联的 L2 文档路径

3. 读目标 L1 文档，提取：
   - 输入/输出定义（请求体结构、字段、类型）— 作为用例"输入"字段的结构基准
   - 如果 L1 或 L0 链接了 proto/OpenAPI 文件，读取该文件获取完整的请求/响应字段定义
   - 业务规则（逐条编号）
   - 错误场景
   - 可观测状态
   - "已有测试覆盖"章节（已覆盖/未覆盖维度）

4. 读关联 L2 文档，提取：
   - 新增/变更规则
   - 测试重点
   - "已有测试覆盖"章节

5. 搜索已有用例，确定编号起点：
   - 新结构优先搜索已指定 suite 目录、`test_workspace/suites/` 中绑定该 module 的 suite，以及 `aitest.yaml.workspace.paths.suites_dir`
   - 找到该模块缩写的最大 TC 序号，新用例从 +1 开始

6. 读 `aitest_config/refs/assertion-strategy.md`，建立断言策略（结构断言 / 关系断言 / 不可程序化断言的选择标准）

### 第二步：第一轮——业务用例（不看代码）

**信息边界：本步骤禁止读取源代码文件（.py/.java/.go/.ts 等）。**

1. 遍历 L1 "业务规则"章节，每条规则至少生成一条用例
2. 遍历 L1 "错误场景"章节，生成异常用例
3. 遍历 L2 "新增/变更规则"，为新规则生成用例
4. 检查排除场景列表 → 跳过匹配的场景类型
5. 检查关注场景列表 → 逐项确认已覆盖
6. 跳过"已有测试覆盖"中标注为已覆盖的维度（避免与历史用例重复）
7. 知识库没说的行为 → 预期结果写 `TBD-需确认`，不猜测
8. 用例的"输入"字段必须基于 L1 文档的输入/输出定义，写出完整请求体结构；L1 未给出完整字段定义的，标注 `[!请求体待补全]`
9. 前置条件必须写出具体构造方式（配置片段、管理 API 请求、测试数据记录、外部依赖状态等），不能只写抽象描述
10. 区分可控输入与系统中间产物：请求参数、配置、测试数据、外部依赖状态属于可控输入，可在前置条件中指定具体值；系统运行时计算结果（如派生值、聚合值、排序位次）属于中间产物，不能在前置条件或场景变量中假设其具体值，只能通过调整可控输入间接影响；对中间产物的断言必须使用范围断言或关系断言
11. 断言选择遵循 `aitest_config/refs/assertion-strategy.md` 的三种策略

**接口覆盖**：查看 L1 "接口"章节，确认模块暴露的接口类型（HTTP / gRPC / 两者）。共享配置可以列出多种接口，但默认 Markdown 用例只生成 JSON 基础请求体；写 `协议：gRPC` 或 `基础请求体（gRPC）` 不会阻断默认 JSON 路径，真实 gRPC、SDK 或多端点执行再在后续 suite profile 中通过 `case_flows` 或 `case_bodies` 显式接线。

**输出格式**：默认输出到 `$suite_dir/business.md`；如果用户指定需求 suite，可输出为 `{suite_name}_business.md` 等带语义的文件名。按 `aitest_config/refs/case-format.md` 的"共享配置 + 精简用例"格式。每条用例只写 **优先级 / 场景变量 / 断言** 三个字段（有特殊状态时加 **标记** 字段）。场景变量必须写成 `key：value` 条目列表，`[manual]`、`[!可行性存疑]` 等标记写在独立的标记字段，不内联到场景变量或断言中。test-design 只产出 Markdown 用例，不写 `suite.yaml` 和 suite profile；这些由 `test-scaffold` / `test-codegen` 接线。

### 第三步：第二轮——边界用例（读代码）

1. 通过 Glob/Grep 搜索项目中与 `$target/$module` 相关的源代码文件
2. 读源代码，识别以下边界场景并生成用例：
   - 降级逻辑（try/except、默认值返回）
   - 类型转换（隐式转换、强制转换）
   - 容错处理（空值、None、空列表）
   - 精度处理（round、截断）
   - 未在知识库中记录的条件分支
3. 校验第一轮用例的可行性：
   - **HTTP 路由校验**：如果 `target.yaml` 声明了 `service.route_patterns`，按该模式搜索路由；否则以文档、OpenAPI/proto 或用户指定入口为准，必要时标 `[!可行性存疑]`
   - **请求体 Schema 校验**：如果 `target.yaml` 声明了 `service.schema_patterns`，按该模式搜索 Schema；否则读取 OpenAPI/proto/JSON Schema 等公开接口定义，逐字段核对请求体（必填字段必须存在，嵌套结构也要检查）
   - 前置条件是否可通过代码构造
   - 输入格式是否与代码接口匹配
   - 补全标注了 `[!请求体待补全]` 的用例
   - 有问题的用例追加标注 `[!可行性存疑: 原因]`
4. 发现规格与实现不一致时 → **不修改第一轮用例**，按 `aitest_config/refs/mismatch-format.md` 新建 mismatch 记录。如果 `$suite_dir/mismatch.md` 已存在，新条目**追加在文件末尾，不删除/覆盖已有条目**，编号从已有最大序号 +1 继续
5. 第一轮中标记 `TBD-需确认` 的预期结果，如果代码能给出答案，在 business.md 中更新并标注来源

默认输出到 `$suite_dir/boundary.md`，使用与 business.md 相同的共享配置格式；suite 模式可使用 `{suite_name}_boundary.md` 等带语义的文件名。
Mismatch 输出到 `$suite_dir/mismatch.md`（无则不创建）。

### 第四步：覆盖变更与知识库刷新

1. 汇总本次新增用例覆盖的维度
2. 对比 L1/L2 文档"已有测试覆盖"章节中的"未覆盖"列表
3. 在 business.md 和 boundary.md 末尾各附覆盖变更清单：

```markdown
## 覆盖变更

| 知识库文档 | 新增覆盖 | 仍未覆盖 |
|-----------|---------|---------|
| L1/xxx | 维度 A、维度 B | 维度 C |
```

4. 更新 L1/L2 文档的"已有测试覆盖"章节：
   - 将新覆盖的维度从"未覆盖"移到"已覆盖"
   - 添加用例文件引用

### 第五步：完成输出与反馈收集

执行完毕后，向用户输出：

```markdown
## 用例生成摘要

目标：$target
目标模块：$module
输出目录：$suite_dir

### 生成文件
| 文件 | 用例数 | 类型 |
|------|-------|------|
| business.md | N 条 | 业务 + 异常 |
| boundary.md | N 条 | 边界 |
| mismatch.md | N 条 | 规格偏差 |

### 覆盖变更
| 知识库文档 | 新增覆盖维度 | 仍未覆盖维度 |

### TBD 项
（列出所有预期结果为 TBD-需确认 的用例，需用户或产品确认）

### 可行性存疑
（列出所有标注了 [!可行性存疑] 的用例）
```

然后询问用户：
1. 请评审用例，有无需要调整的
2. 有没有不值得测的场景类型？（补充到 TEST_SPEC 排除场景）
3. 有没有遗漏的必测场景？（补充到 TEST_SPEC 关注场景）

如果用户给出排除/关注反馈 → 更新 `{paths.test_spec}` 对应章节。

## 质量自检

生成每条用例后，对照以下两组规则逐条检查，不通过的用例必须修正后再输出：

1. **TEST_SPEC 质量红线**（Q1-Q10）— 用例可执行性的硬性要求
2. **TEST_SPEC 已知陷阱**（**全部条目**，不限于已编号的最早三条）— 历史错误模式自检；陷阱列表会随 test-fix 持续扩展，每次生成时读取当前完整列表逐条核对

## 增量模式

当 `$suite_dir` 下已有 business.md 或 boundary.md 时，**先询问用户选择处理方式**：

- **追加新用例**：识别已覆盖场景，追加新用例到末尾
- **重新生成**：把已有文件备份为 `*.md.bak`，从零生成全部用例

用户选择追加时，继续询问**用例来源**：

- **从知识库补充**：自动从知识库识别未覆盖场景，生成新用例（原有逻辑）
- **手动描述补充**：用户用自然语言描述想要添加的测试场景，AI 翻译为符合格式规范的用例写入 Markdown

**格式兼容检测**：检查已有文件是否包含 `## 共享配置` 块。
- 是新格式 → 按用户选择执行
- 是旧版完整格式 → 追加模式会破坏共享配置语义；停下来明确告知用户，建议改为"重新生成"或先手动迁移已有用例

确认选择后再执行。

### 追加模式——从知识库补充

1. 读取已有用例，理解已覆盖的场景
2. 只生成未覆盖的新用例
3. 新用例追加到已有文件末尾（覆盖变更清单之前）
4. 编号从已有最大序号 +1 继续

### 追加模式——手动描述补充

1. 读取已有用例文件，理解共享配置和已有用例的格式
2. 请用户描述要添加的用例（可以一次描述多条），接受自然语言，例如：
   - "加一条测试：当资源余量为 0 时请求接口，应该返回空列表"
   - "补一个边界：user_id 为空字符串的情况"
   - "测试并发场景：同一用户同时发两个创建请求，不应重复创建记录"
3. 根据用户描述，结合已有共享配置和项目上下文，生成符合 `case-format.md` 格式的用例：
   - 编号从已有最大序号 +1 继续
   - 复用已有共享配置（接口、基础请求体等）
   - 场景变量写成 `key：value` 条目列表
   - 断言选择遵循 `assertion-strategy.md` 的三种策略
   - 用户描述中不明确的部分主动询问，不猜测
4. 生成后展示给用户确认，确认后写入对应的 Markdown 文件
5. 对生成的用例执行质量自检（TEST_SPEC 红线 + 陷阱）

### 重新生成的执行规则

1. 把已有 business.md / boundary.md / mismatch.md 改名加 `.bak` 后缀
2. 按完整流程从零生成，编号从 001 开始

