流程位置:
pm-master阶段9 测试用例 /dev-master阶段9 测试;也可单点直接调用。 (两条流程的阶段号不同,按当前在跑的那条读。) 流程内落盘路径prd/test/{日期}-{项目}-测试用例-V{版本}.md(流程门禁按 glob 匹配,命名带产品名/日期是正常的)。 上游读SPEC_SOURCE(SRS/PRD),与pm-ai-ship-audit的derive-tests覆盖地图对齐(dev-master阶段11;pm-master已无审计阶段)。
测试用例生成器
角色定义
以资深测试工程师视角工作:
- ✅ 测试用例覆盖业务功能、异常、性能、权限四个维度
- ✅ 预期结果必须具体明确,不能写"显示正确"、"操作成功"
- ✅ 异常测试覆盖所有必填字段、格式校验、关联数据约束
- ❌ 不只测试正常流程,不忽略边界条件
- ❌ 不遗漏关键业务场景(删除已关联数据、重复提交等)
详细的表格规范和覆盖场景参考:references/test-cases-guide.md
执行流程
Step 0: 扫描项目上下文
先主动扫描项目,找到已有文档再开始工作:
| 优先级 | 文件类型 | 查找方式 |
|---|---|---|
| 最高 | 需求说明书 | Glob("**/*需求*说明书*.md") |
| 高 | 功能清单 | Glob("**/*功能*清单*.md") |
| 低 | 路由/代码 | src/router/, src/views/, src/api/ |
默认全量覆盖所有找到的功能模块,只有文档完全缺失时才询问用户。
Step 1: 读取模板
读取 references/templates/test-cases.md,按模板结构生成文档。
Step 2: 生成任务清单
必须先展示任务清单,再逐个生成,禁止一次性写入整个文档。
任务拆分原则:拆到最小粒度,每个功能模块的每类测试(业务功能、异常、性能、权限)都是独立任务。
任务清单示例:
| 序号 | 任务名称 | 状态 |
|------|---------|------|
| 1 | 创建文档骨架 | ⏳ 等待中 |
| 2 | 6.1.1 设备档案 - 业务功能测试 | ⏳ 等待中 |
| 3 | 6.1.1 设备档案 - 异常测试 | ⏳ 等待中 |
| 4 | 6.1.1 设备档案 - 性能测试 | ⏳ 等待中 |
| 5 | 6.1.1 设备档案 - 权限测试 | ⏳ 等待中 |
| 6 | 6.1.2 设备分类 - 业务功能测试 | ⏳ 等待中 |
| 7 | 6.1.2 设备分类 - 异常测试 | ⏳ 等待中 |
...
| N | 七、测试总结 | ⏳ 等待中 |
执行规则:
- 每次只生成一个任务,生成前更新为 🔄,完成后更新为 ✅,重新展示清单
- 任务1(文档骨架)用 Write 创建文件,后续用 Edit 追加
- 每条用例使用卡片式表格(
^合并语法),格式参考references/test-cases-guide.md
Step 3: 质量检查
生成完成后自检:
- 每条用例的预期结果具体明确
- 每个必填字段都有"为空"的异常测试
- 每个有权限控制的功能都有权限测试
- 删除/修改操作都有"二次确认"验证
- 用例编号无重复
Step 4: 导出文档(可选)
⚠️ 导出前后各一件事:① 图片必须放在文档同级的
images/子目录且文件名纯 ASCII——这是唯一可用形式,img/、images/sub/、../images/、与文档同目录、中文名全都静默丢图(脚本仍打印Export succeeded,但word/media/是空的);② 导出后立刻验unzip -l <docx> | grep -c "word/media/",数字必须等于图片张数。实测边界表见../common/README.md。
Windows(PowerShell): ../common/export-word.ps1 <markdown文件路径> test-cases
跨平台: python ../common/export-word.py <markdown文件路径> test-cases
Git Bash: bash ../common/export-word.sh <markdown文件路径> test-cases
文档命名规范
prd/test/{日期}-{项目名称}-测试用例-V{版本号}.md
示例:prd/test/20260330-智慧厂区巡检系统-测试用例-V1.0.md(研发链跑同一技能时落 dev/test/)
修订:就地改也要改文件名。 不论体量大小一律就地 Edit 改(大文档尤其别整份重写,小文档也不要另存新文件)——目录里永远只留最高版本那一份;改完必须三样一起动——文首「文档版本」、版本记录表、mv 把文件名的版本号也改掉(局部修订 +0.1,结构性重写进大版本;日期取改动当天)。**绝不允许内容已是 V1.1、文件名还写 V1.0。**改名后 grep 一遍旧名,把 README 清单、下游「来源」行、tools/ 脚本里的引用一并改掉。完整规则见 ../common/README.md。
参考资源
- 测试用例模板:
references/templates/test-cases.md - 表格规范和覆盖场景:
references/test-cases-guide.md
输入来源:设计稿也是合法输入
主真源仍是 SRS / PRD。但项目若已有过了闭环检查的设计稿(design-system/),必须一并读——
它能补出文档里没有的两类用例,漏读等于少一半覆盖:
| 读什么 | 能多出什么用例 |
|---|---|
FLOWS.md |
每条流程的失败与取消分支(文档常只写好天气那条)、中间态(loading / 遮罩 / Toast) |
HANDOFF.md 第 4 节状态矩阵 |
七态逐页覆盖:空 / 加载 / 错误 / 无权限 / 部分字段缺失 / 超长超多数据 |
HANDOFF.md 第 5 节 |
表单校验的正则、触发时机、错误文案——边界用例照它写,不要自己编 |
CONSISTENCY.md |
多端项目的差异点,按端各出一组用例 |
设计稿与 SRS 冲突时取 SRS,并在用例的「备注」列记一行差异,别闷着按设计稿写。
真源里有状态机表时,逐行转成用例(最容易漏的一类)
SRS/PRD 里若有业务对象状态机表(订单、审核、退款、工单、提现、内容发布;
PRD 侧见 pm-prd-spec 的 T14,SRS 侧在 2.4 业务流程图与各 3.5.x「状态与权限说明」),
逐行生成两类用例,一行都不能跳:
| 从哪一列来 | 出什么用例 | 例 |
|---|---|---|
| 当前状态 + 触发事件 + 新状态 | 正向流转用例:在该状态下执行该事件,断言状态变为新状态 | 待审批单据点【通过】→ 状态变「已通过」 |
| 副作用列 | 副作用断言(并到上面那条里,不单独成条):数据变化、通知是否发出 | 通过后 1 分钟内自动入账、短信已发出、流水已写入 |
| 「此状态下不允许的操作」列 | 非法操作拦截用例——每个不允许的操作各一条 | 对「已入账」单据调编辑接口 → 拒绝并提示,余额不变 |
| 超时/系统自动流转行 | 时效用例:把时间推到阈值后,断言自动流转与通知 | 待审批满 72 小时 → 自动「已过期」,通知提交人 |
- 非法操作拦截那一类最容易整块漏,而它正是线上事故高发区(绕过界面直接调接口改已完结的单据)。 它属于「权限测试」还是「异常测试」不重要,关键是别因为界面上点不到就不写。
- 状态机里的每个状态至少被一条用例覆盖到,终态要验证"确实不能再流转"。
- 表里没有的流转要当成缺陷提出来("驳回后能否重新提交"没写),不要自己假设一个补上。
外部依赖与降级:Word/xlsx 导出
导出链走技能库根的 config.json 里的 apiBaseUrl(端点不随仓库分发,取值见该文件)。
| 情况 | 表现 | 怎么办 |
|---|---|---|
没配 config.json |
脚本报「无法从 config.json 读取 apiBaseUrl」 | 从同级 config.example.json 复制后填地址 |
| 服务没起 | curl 连不上 / 超时 |
先自检(在技能自己的目录下跑):curl -s -o /dev/null -w '%{http_code}' "$(python3 -c 'import json;print(json.load(open("../config.json"))["apiBaseUrl"])')/",连得上就行(/ 不是路由,返回 404 也算通;连不上才是服务没起),起服务后重试 |
| 两者都缺 | —— | 降级交 md,并在交付清单里写明「Word 未导出(端点未配)」 |
三条不许:不许把「导出失败」写成完成;不许跳过导出直接说交付完成;
不许在导出后不验图——unzip -l x.docx | grep -c 'word/media/' 要等于文档里的图片张数(文件名含中文会静默丢图)。