让 AI 参与测试:能做什么、不能做什么
AI 在测试上最强的地方,是把一条已经说清楚的判断批量展开成用例;最弱的地方,是替你做出判断。这两件事分清了,AI 参与测试的收益立刻为正;分不清,就会拿到一堆永远绿灯、也永远抓不到缺陷(bug)的测试文件。
1. 能力边界对照表
| 任务 | AI 表现 | 原因 | 必须由人做的事 |
|---|---|---|---|
| 按签名补表驱动用例 | 强 | 模板高度确定 | 补上业务特有场景 |
| 生成通用边界值(0/负/空/超大/Unicode) | 强 | 属于通用工程常识 | 判断哪些边界在本业务里合法 |
| 写桩(stub)与假实现(fake)骨架 | 强 | 接口即契约,生成成本低 | 判断替身行为与真依赖是否一致 |
| 断言「业务上应该是什么」 | 弱 | 模型没有你的领域上下文 | 全部 |
| 判定金额、时区、权限的期望值 | 弱 | 领域规则不在训练数据里 | 全部 |
| 决定覆盖率与性能的验收阈值 | 弱 | 阈值是团队决策,不是知识 | 全部 |
| 读报错猜原因并给最小复现 | 中 | 会编造不存在的栈帧与字段 | 提供真实日志并核对结论 |
一句话:AI 产出的是「候选用例」,不是「正确答案」。
2. 把验收标准当输入,而不是当结果
提示词里必须写清「输入 → 期望输出」的契约,契约来自需求条目、接口文档或校验规则;绝不能先跑一遍实现、再让 AI 照抄输出当期望值。后者会把现存缺陷一起固化进测试。
角色:Go 测试工程师。
输入:下面的函数签名与规格说明。
要求:
1. 只用表驱动 + t.Run 子测试,不引入第三方断言库;
2. 每个用例写明 name、输入、期望值、期望错误(用 errors.Is 判断);
3. 覆盖正常值、边界值(0、负数、上限、上限+1)、错误路径、Unicode;
4. 不要修改被测函数,不要运行代码后把输出当期望值;
5. 规格没定义的行为,单独输出「需人工确认」清单,不要自行编造。
函数签名:
func Discount(amount int64, level string) (int64, error)
规格:
- amount 单位为「分」,必须 >= 0,否则返回 ErrInvalidAmount;
- level 只接受 "vip" 与 "normal",其它值返回 ErrUnknownLevel;
- 折扣率:vip 九折、normal 不打折,结果向下取整到分;
- amount 上限 1000000000000 分。
第 5 条是关键:要求它列出「需人工确认」,而不是自己决定,这一句能挡掉大部分幻觉断言。
3. 验收 AI 产出的第一步:弄红实验
拿到测试后先别评审写法,做一次「弄红实验」——故意改坏实现的一行,跑测试看它是否变红。
func TestDiscount(t *testing.T) {
cases := []struct {
name string
amount int64
level string
want int64
wantErrIs error
}{
{"vip 九折", 10000, "vip", 9000, nil},
{"normal 不打折", 10000, "normal", 10000, nil},
{"零元不打折", 0, "vip", 0, nil},
{"负数金额", -1, "vip", 0, ErrInvalidAmount},
{"未知等级", 100, "gold", 0, ErrUnknownLevel},
{"上限金额", 1000000000000, "vip", 900000000000, nil},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got, err := Discount(tc.amount, tc.level)
if !errors.Is(err, tc.wantErrIs) {
t.Fatalf("Discount(%d,%q) err = %v, want %v", tc.amount, tc.level, err, tc.wantErrIs)
}
if err == nil && got != tc.want {
t.Errorf("Discount(%d,%q) = %d, want %d", tc.amount, tc.level, got, tc.want)
}
})
}
}
把 vip 的 0.9 改成 0.95,测试必须红。如果全绿,说明断言是照着实现抄的——测试只是实现的复印件,还会拖慢每次重构。
4. 三件绝不交给 AI 的事
- 业务语义的正确性:退款金额怎么算、跨时区的时间归属哪一天、权限矩阵里谁能看谁的数据,只有需求方与你能定。
- 期望值的来源:期望值来自规格而不是「程序现在的输出」。用输出当期望,等于把现有缺陷固化成「正确行为」。
- 验收阈值:覆盖率下限、压测 P99 目标、允许的错误率,这些是决策,不是可检索的知识。
5. 常见坑
- 套话式断言:只断言
err == nil、只断言响应体非空。AI 很爱写这种「结构性测试」,它什么都证明不了。 - 隐含假设:默认输入是 ASCII、时间不含夏令时、金额可以用 float。你的业务未必如此。
- 不可重复:产物里带
time.Now()、rand.Int()、time.Sleep,第二次跑就变红。要求它显式注入时钟与随机源。 - 编造的接口:模型可能调用不存在的字段、伪造不存在的错误变量。验收先跑
go build ./...与go vet ./...。 - 测试实现细节:断言私有字段、把调用次数写死到具体实现路径,重构一次全红。测试应盯契约,不盯写法。
小结:AI 在测试上是一个高产的「用例候选生成器」,产出质量取决于你喂进去的验收标准有多清楚;用它批量生成、用人工修订期望值、用「弄红实验」验收,把业务语义与阈值始终留在人手里——这就是整套「用 AI 驱动测试」的起点。