write-testslisted
Install: claude install-skill ai798-Lab/karman
# 给功能补测试用例
**这个 skill 的价值不在「生成测试」,在「证明生成的测试有用」。**
有一份 30 人的对照实验(arXiv:2502.09801):限时一小时给一个含 38 个已知缺陷的系统写测试。用 AI 的一组人均写出 59.3 个测试、分支覆盖率 26%、找到 6.5 个缺陷,三项都碾压手写组的 27.1 个、16%、3.7 个。但**假阳性也从人均 2.7 涨到 5.1**。论文自己做了相关性分析后给的结论很诚实:假阳性变多主要是因为写得多了,不是 AI 让每个测试变差。
翻译成人话:**AI 让你一小时多出一倍的测试,也多出一倍的误报,分诊成本同比例上升。**所以这个 skill 把重心放在后两步。
## 铁律三条
1. **产出必须是代码文件。**不管第一步用什么方式探索的,落盘的一定是可以重复执行的测试代码。原因是这些用例要被跑几百次,而靠模型逐帧点击跑一次三十步的流程要几分钟、几美元、且两次结果可能不同。
2. **先确认核心路径是对的,再让 AI 补测试。**顺序反了就是让它把 bug 当成规格固化下来。
3. **不能证明有效的测试,删掉。**变异自检不变红的用例,留着只会增加维护成本和误报。
## 第 0 步 · 一条容易被忽略的前提
有一份 2026 年的研究(arXiv:2607.22880,11 个模型、10 万多个测试用例)发现:
- 对**没有 bug 的代码**生成测试,分支覆盖率和缺陷发现能力强相关
- 但如果**代码本身带 bug** 再让模型生成测试,这个相关性全面变弱
原因不难理解:模型会把当前行为当成期望行为写进断言。**所以先自己手动走一遍核心路径确认是对的,再让 AI 补测试。**这一步跳过了,后面的覆盖率数字会骗你。
**怎么算「确认过了」**:要能用一条产品语义对上,也就是「输入 A 必须得到结论 A」,
而不是「跑起来没报错」。举个真实例子:某个测评的题库选项是按四个季节的顺序排布的,
所以「全选第 n 个选项必须落到第 n 个季节」,这个期望值来自题库设计,不是从实现里算出来的。
**如果确认过程中真的发现了缺陷(大概率会),三选一**,不要卡在这里:
| 情况 | 怎么办 |
|---|---|
| 能当场修,且属于本次范围 | 先修再写测试 |
| 不属于本次范围 | **按正确行为写好断言,标记为预期失败**(比如 Node 测试跑器的 `{ todo }`、Vitest 的 `test.fails`),基线仍算绿 |
| 确认不了对错 | 写进测试计划的存疑区,不下断言 |
| 缺陷不在被测模块内,是你路过看到的 | **只写进交付报告给源码作者,不下断言、不扩大范围。**跨模块的 todo 断言会让缺陷的归属和维护者错位,以后��都不敢删 |
第二种最常用。这样缺陷被记录在案、每次跑都会提醒,而第 4 步的变异自检仍然有一个绿基线可用。
**用 `{ todo }` 之类的标记时,在交付物里注明一句**:这条会打印在失败列表那一段里,但退出码仍是 0,
看统计行的失败数,别看有没有红叉。否则下一个人以为基线是红的。
**真实环境跑不动怎么办**(服务端补测试的常态:本机起不了数据库、连线上库会写脏数据、
调真上游要钱)。这时第 0 步不是跳过,是换一种做法:
1. 先从**最接近运行时的东西**里抽出至少一条独立真值来源:数据库结构定义、迁移文件、类型定义、验收清单
2. 写一个**只打印末态、不下任何断言**的探路脚本,把核心路径