AI reviewer 证明修复生效了。它没有。
Curbside devlog #1——一个 Unity 6 合作游戏("和朋友们一起烂偷车"),用三 agent 循环开发。这篇不聊游戏,聊作者花了两周才学会:测试套件在骗他——而且连专门抓"说谎测试套件"的变异测试都没抓到。
三 agent 严格分工
- Architect 写 spec:哪个模块拥有该功能、跨哪个接口、哪个 peer 决策、什么能证明它工作。不写代码;
- Builder 实现 spec:不设计接缝、不打分自己;
- Critic 冷眼评审,没见过 Builder 的推理。任务就是证明功能不工作。
让 Critic 有用的规则是举证标准:变异,不是阅读。它不许说"这个测试看着弱",必须指出要破坏哪行、哪个断言应该随之失败——然后真去破坏它跑套件。能描述一个让套件保持全绿的生产代码改动,就是发现,不管测试读起来多好。
这套机制真抓到了东西:一个入口没有调用者的 mechanic 功能,在全绿套件下发布了——测试覆盖了一个没有任何东西能触达的功能的每条规则。
变异测试失手的案例
游戏里一辆车缺一个轮子:玩家扛轮子回来按上,车就能开。多人时服务器决定一切,客户端只请求不行动。bug:车在装轮时被摧毁,轮子该掉下来回到原位,否则轮子焊死在尸体上、mechanic 悄悄消失。
守卫逻辑:
private void OnDestroy ()
{
if (! DecidesHere ()) { return; } // 只有决策 peer 才 un-stow
_wheel . Unstow ();
}
测试写好,套件 161/161 全绿。变异:删掉 Unstow() 调用,测试失败——按设定的标准证据完整。bug 还在。
为什么:DecidesHere() 问 FishNet 这个 peer 有没有权威,读的是 NetworkObject 的 initialised 状态。FishNet 的销毁顺序是先 Deinitialize 再 Destroy——对象在销毁前已反初始化。于是 OnDestroy 运行时,"我有权限吗"的诚实答案是已经变成否:守卫静默短路,轮子留在尸体上。变异测试打的桩恰好和真实失败路径在时间上错开。
实践建议
- 评审 agent 用变异举证而非读代码:能说出"改哪行会让套件仍绿"才算发现;
- 变异测试不是终点:变异覆盖不到"状态已变而断言恰好绕过"的时序类 bug;
- 守卫条件要问"此刻的决策者是谁"而不是"曾经是谁"——销毁/反初始化顺序是时序 bug 高发区。
来源:My AI reviewer proved the fix worked. It didn't. - DEV Community