让 AI Agent 帮你写测试、跑测试,你多半收到过一句令人安心的提示:「全部通过(All Passed)」。但很多时候,事后查验才会发现,这句承诺漏洞百出。
这篇文章记录了三次「全部通过」被无情拆穿的过程。所有的数字和日志都真实存在,未作修改。文章最后,总结了三个针对「假通过」的硬核解法。
(背景提示:事情发生在一台 Windows 测试机上,几个 AI Agent 正分头协作,将一个名叫 Polter 的多 Agent 终端应用移植到 Windows 平台。)
第一次「假摔」:号称 16 个通过,其实 3 个根本没碰到
当时的界面上排布着 17 个标签(Tab)。测试 Agent 写了一段脚本,挨个去点击这 17 个标签的中心点。
一开始,Agent 自信地汇报了战况:
- 系统播报:
17 tabs, 1 mismatches - 字面意思:只有 1 个报错,其余 16 个完美通过。
但仅仅四分半钟后,写测试的 Agent 自己推翻了这行读数:真正被有效检验过的,只有 13 个。
| 标签状态 | Agent 最初汇报 | 真实情况 | 假警报原因 |
|---|---|---|---|
| 第 1~13 个 | 成功 | 成功 | 正常点击,没问题。 |
| 第 14 个 | 失败 | 成功 | 界面太挤,标签中心点被右侧的「+」按钮盖住了,点错位置了。 |
| 第 15~17 个 | 成功 | 未测试 | 坐标已超出屏幕边界,物理上根本点不到,测试函数“闭眼”报了通过。 |
为什么 15~17 号标签会被标记为通过?因为测试脚本只是去问了代码内部的判定函数,函数闭着眼睛回了一句ok。它看似全绿,其实一个像素都没真正测到。
Agent 留言录:
“报假警报的测试,好歹还会让人看一眼;而报0 mismatches的测试,往往是让代码失去信任的最快方式。”
修复之后,测试结果不再是非黑即白的过与不过,而是变成了三个维度的真实数据:17 tabs, 13 ok, 0 mismatches, 4 untested
第二次「盲区」:盯着一个永远不会变的像素点
第一次是测试脚本在自欺欺人,第二次则是测试标准定得极其荒谬。
为了测试「窗口拉大时,画面能不能及时跟上」,Agent 制定了如下判定标准:
- 扩大窗口尺寸。
- 检查拉大前后,窗口中心点的像素颜色是否发生变化。如果没变,说明画面跟上了。
从数据上看,窗口尺寸从984x631变大到了1224x751,中心点颜色一模一样。测试完美通过!然而,这个测试在 Bug 存在的情况下,安然无恙地「全绿」了一整天。
当天下午,换了一种测量方式后,真相大白:当窗口被拉大时,新增的边缘区域全是黑屏,画面渲染其实失败了。但因为旧画面一直固定在左上角,无论怎么拉大,原本的「中心点」永远都会落在旧画面里。
| 测试标准 | 测量位置 | 结果 | 缺陷 |
|---|---|---|---|
| 旧标准 (假绿) | 固定的窗口「旧中心点」 | 永远通过 | 就像蒙上了眼睛,去验证光的存在,完全看不到边缘的黑屏。 |
| 新标准 (真抓) | 算出「新露出来的边缘区域」,测新区域像素 | 真实报错 | 因为新区域的像素,绝对不可能来自上一帧画面。 |
第三次「幽灵」:它之所以绿,是因为根本没触发
前两次的测试好歹还在机器上跑了,第三次,在报出「全绿」的那台机器上,根本连跑都没跑过。
当时团队在修一个 Windows 独有的 Bug(子进程输出权限被 AutoRun 配置拦截)。为了防止 Bug 回归,Agent 写了一条测试:让子进程去尝试输出,能输出就是ok。
这条测试在 macOS 开发机上跑,永远是全绿通过。提交代码的 39 分钟后,在 Windows 真机上第一次跑,直接爆红失败。
| 运行环境 | 测试结果 | 真实原因 |
|---|---|---|
| macOS (开发机) | 全绿通过 | macOS 压根没有 Windows 的 AutoRun 机制,这条容易报错的代码路径连碰都没碰到。 |
| Windows (真机) | 爆红失败 | 环境触发了拦截机制,真实暴露了 Bug。 |
Agent 留言录:
“一个专门为了「看机器环境决定的 Bug」而写的测试,在原本就安全的机器上跑出来的绿,什么也证明不了。”
怎么知道自己在被骗?三个现成的解法
总结这几次发现假测试的路径,有一件事非常显眼:没有哪一次,是通过把原来那条绿色的测试再跑一遍来发现问题的。
你要怎么知道一条测试是不是在骗你?Agent 给出了一个极其精准的判别法:
“不要问『这条测试通过了吗?』。你要问:『如果被测的那个东西坏了,这条测试能看得见吗?』”
在当时的开发记录里,这句话最终落地成了三个非常具体的做法,可以直接抄作业:
1. 汇总行必须报三个数
不要只报「通过」和「失败」。没有被触发的代码,绝不能被藏在ok的数字里。
- 通过 (OK)
- 不符 (Mismatch/Fail)
- 没测到 (Untested/Skipped)——三个数加起来,必须等于总数。
2. 「预期为空」的旁边,绑一条「预期非空」
如果你测试的标准是“日志里没有报错”,这可能意味着没报错,但也可能意味着代码压根就没运行!
断言必须有底线:你可以要求没报错,但必须同时断言**“程序确实执行到了这里”**(比如要求某个常规启动日志至少出现一次)。如果没有,一律记作「没测到」。
3. 故意改坏代码,看测试红不红(最硬核)
写完测试后,故意把被测逻辑改错(比如把取点位置写偏,或者强行制造异常)。如果代码明明坏了,测试依然是绿的,说明这个测试根本就是瞎的。每一次主动制造的红,都是为了证明下一次的绿有意义。
下次如果你的 AI Agent 潇洒地告诉你0 failures时,记得接着问它两个数字:
“跳过了几格?有几格根本没跑到?”