绿灯亮了,但老张想起了那次事故

老张有一个习惯:每次代码合入前,他会看一眼自动化测试的结果。如果那个绿色的 CI 通过信号亮着,他基本就放心了。
直到有一次,那个绿灯差点骗了他。
那次差点出事
事情是这样的。
团队改了一个功能——一个关于订单审批的规则调整。改动提交后,自动化测试跑了一遍。结果:CI 任务全部执行完成,绿灯。 老张扫了一眼,准备合入。
合入之前,他出于习惯,多点进去看了一眼测试的详细结果。
他看到了一个不对劲的地方。
测试列表里,有一类用例叫"正例"——意思是应该被审批通过的订单。这些正例,预期结果是"通过"。老张点开看,发现有几个正例的实际结果是"待复核"——也就是说,系统没有直接通过它们,而是把它们扔进了人工复核队列。
从 CI 的角度看,这件事毫无异常——流水线跑完了,没有报错,状态是 completed,绿灯。问题在于,当时的流水线只检查了流程是否跑完,没有断言每笔订单的业务结果对不对。但从"业务正确性"的角度看,这是一次业务回归——影响可控,但确实错了:一个本该自动通过的订单,被错误地卡住了。如果这个版本上了线,真实的客户就会遭遇"明明合规的订单,却被要求人工复核"。
老张盯着那个"待复核"的结果,他意识到现有检查漏了业务断言。
让他发凉的不是这个 bug 本身——它不算大,改起来也快。让他发凉的是:那个绿灯,差点让他相信一切正常。 如果他那天没有多点进去看一眼详细结果,如果他就停在 CI 绿灯那个信号上——这个回归就上线了。
"完成了"和"正确了",是两回事
那天晚上,老张想了很久,想明白了一个一个工程上需要补的漏洞。
"测试全部通过"(completed)和"功能正确"(correct),是两个完全不同的概念。 但那个绿色的"全部通过",把它们混为一谈了。
"全部通过"只证明了三件事:系统没崩、流程跑通了、没有报错。它完全没有证明的是:系统对每一笔订单做出的判断,是不是对的。
一笔本该"通过"的订单,可能进了"待复核";一笔本该"驳回"的订单,可能被"通过"了。只要系统在"执行",这些错误的判断就会和正确的判断一起,被笼统地打包成"全部通过"。
这就是那个绿灯骗人的本质:它是一个"执行层"的指标,却被人误读成了"业务层"的保证。
老张打了个比方。这就像体检——体检报告说"各项指标正常",你以为是"你很健康"。但其实它只证明了"这几项检查的项目没异常",不等于"你没有任何健康问题"。有些毛病,不在检查项目里。
老张的"门禁"

想明白这件事之后,老张做了一次彻底的改造。
他不再满足于看"全部通过"这个绿灯。他要求:测试不仅要"跑完",还要"断言结果是对的"。
具体怎么做?他给验收定了几条硬规则。只要命中任何一条,就算测试状态是"全部通过",验收也判定失败:
- 测试超时,或某个用例失败;
- 出现报错;
- 本该"通过"的订单,进了"待复核"或"驳回"(被错误地卡住了);
- 本该"驳回"的订单,被"通过"了(被错误地放行了);
- 声明要测的场景里,有没跑到的(场景清单由人在工单里列出,阿行逐项执行并回填证据);
- 测试跑的代码版本,和要验收的版本对不上。
老张特别强调了第 3 条和第 4 条——这才是整个门禁的关键。它们不再检查"系统跑没跑",而是检查**"系统判断得对不对"**。
一笔本该通过的订单进了待复核,不再是"系统正常的谨慎",而是"一次必须失败的回归"。一笔本该驳回的订单被放行,不再是"流程完成的副产品",而是"一次严重的安全漏洞"。
老张管这套规则叫"门禁"。门禁检查的是业务正确性,不是执行顺利度。业务判断错了,执行再顺利也算失败。
五道关,但人只守最后一道
光有这几条硬规则还不够。老张把整个验收过程,拆成了五道关,一道比一道严格,而且每一道只问一个问题。
| 关 | 谁来把 | 问什么 |
|---|---|---|
| 第一关 | 阿行 | 我这次改的代码,本地测试过了吗? |
| 第二关 | 系统 | 验收环境跑的,确实是要验收的版本吗? |
| 第三关 | 自动化 | 该通过的正例都通过了吗?该驳回的反例都驳回了吗? |
| 第四关 | 阿行 | 这个具体工单的边界场景,我额外测了吗? |
| 第五关 | 人(老张) | 这个功能,真的符合业务预期吗? |
前四关由阿行和自动化执行——但场景清单是人事先定义的,代码合入也由人审批。第五关,是老张做最终的业务验收。
有人问老张:为什么人只守最后一关?是不是人被边缘化了?
老张摇头。他说,恰恰相反——是因为人的判断太宝贵,不能浪费在前四关上。 前四关问的问题,机器都能答:代码有没有破坏、版本对不对、正反例对不对。这些问题,让机器去算。而第五关问的问题——"这个功能符不符合真实业务"——只有浸泡在业务里的人能答。
老张说:把人的参与,推迟到真正需要判断的节点。 机器处理了能规则化的检查,但场景定义、代码审批和最终验收始终需要人。第五关是最后一道,但不是唯一一道人的判断。
失败的时候,现场不能丢
老张还定了一条不那么起眼、但他后来觉得至关重要的规矩:验收失败时,环境不能销毁,要保留下来。
一开始有人不理解——失败了,环境清掉重来不就行了?保留它干什么?
老张说:失败的现场,可用于复现和排查。
如果验收失败后立刻把环境销毁,那老张和阿行就拿不到任何排查依据——他们只知道"失败了",不知道"为什么失败"。而保留环境意味着:老张可以直接进去,看那笔进了"待复核"的订单到底缺了什么、那笔被"通过"的反例到底是怎么溜过去的。保留环境才能复现问题。
这和上一篇讲的"共享环境"是一脉相承的:环境不只是成功时给人验收用的,它更是失败时给人和阿行共同诊断用的。一个会被销毁的现场,等于把每一次失败都变成了黑箱。
老张后来再也没被绿灯骗过
改造完之后,老张养成了一个新习惯。
他看测试结果,不再看那个绿色的"全部通过"。他看的是**"断言结果"那一栏**——每一笔订单的判断,是不是都和预期一致。只要有一笔对不上,不管那个总状态是不是绿的,他都判失败。
那个差点骗了他的绿灯,现在只是一个"执行完成"的提示,不再是一个"业务正确"的保证。两者之间,隔着老张用六条硬规则和五道关搭起来的一座桥。
老张说,他后来最常跟团队讲的一句话是:
"完成"和"正确"必须被强行分开。机器负责把它们分开,人只在分开之后,做最后的判断。
但老张心里,还藏着一个更实际的问题。
门禁拦下的失败记录越来越多。老张开始想:这些失败,能不能反过来变成规则更新的输入? 如果今天某个场景测出了回归,明天能不能自动把"这个场景要检查"加进门禁里?
换句话说——这套系统本身,能不能从自己的错误中学习?
如果今天答错了,明天还会犯同样的错吗?
这是第 7 篇的故事。
一句话结论
"测试全部通过"只证明系统跑完了,不证明结果是对的;六条硬规则和五道关把"完成"和"正确"强行分开,机器负责检查业务判断对不对,人只守最后一道——业务验收。