一句话定义:变异测试(Mutation Testing)是一种用“故意写错代码”来评估测试套件质量的方法——它在源码里制造小 bug,看你的测试能不能把它们抓出来。
它怎么工作
流程很机械:复制一份代码,做一个微小改动,得到一个变异体(mutant)。常见改法有:
- 把
a > b改成a >= b - 把
+换成- - 删掉一行边界判断
- 把返回值
true改成false - 跳过某次变量赋值
然后拿原来的测试跑一遍,结果只有两种:
- 测试失败 → 变异体被杀死(killed),说明测试确实在检查这段逻辑;
- 测试依然全绿 → 变异体存活(survived),说明测试有盲区。
变异分数(mutation score)就是被杀死的变异体占可变异体总数的比例。
打个比方:小区做安保演练,请人扮演小偷去撬门、翻墙、尾随进楼。保安没发现,不代表真被偷了,只说明安保有漏洞。变异测试就是给测试套件请一群“扮演 bug 的演员”。
和代码覆盖率的区别
这是最容易混淆的一对概念。
| 维度 | 代码覆盖率 | 变异测试 |
|---|---|---|
| 回答的问题 | 哪些代码被执行过 | 执行之后有没有真的被验证 |
| 成本 | 低 | 高,要反复跑整套测试 |
| 会不会被糊弄 | 容易,不写断言也能满分 | 很难 |
| 适合场景 | 日常快速反馈 | 核心模块、发布前的测试体检 |
看个例子:
```python
def test_add():
add(1, 2) # 没有断言
```
这个测试覆盖率是 100%,但把 return a + b 改成 return a - b,它照样通过。覆盖率只证明“跑过”,变异测试才追问“检查了没”。
为什么和 AI 生成测试特别相关
让模型写测试很容易,几分钟能生成几十个用例;但模型也容易写出“看着像测试、其实没断言”的东西,甚至断言沿用了实现里的同一个错误假设。变异测试在这里的价值是当考官:把变异体当考卷,AI 写的测试能杀掉多少?如果连 > 改成 >= 都抓不住,回归时大概率也拦不住真 bug。常见做法是让 AI 根据存活的变异体补测试,迭代几轮。
给从业者的建议
不必全量跑。可以只对核心业务逻辑和频繁改动的模块跑,只在 CI(持续集成)里对本次变更的代码做增量变异测试,也可以只启用一部分变异算子。也别追求 100 分:有些等价变异体(equivalent mutant)行为完全一样,永远杀不死。具体阈值和工具配置以官方文档为准。
普通人只需记住一句:测试全绿不等于代码没问题,覆盖率 100% 也不等于。
