一个缺陷,两个独立犯下的相同错误
我手上有一个缺陷,一个模型提出了修复方案,还有一个测试负责给这个修复打分。补丁是错的,测试却让它通过了。两边都不是粗心大意。它们各自读了同一条需求,在同样浅的深度上理解,然后独立地落进了同一个错误位置。那个绿色对勾,是由两个互不相干的错误恰好达成一致才制造出来的。
![]()
我当时正在把已知缺陷分发给不同模型,用机械方式给补丁打分,而不是逐一阅读。这正是测试存在的全部理由:我不想让十三处独立修复都经过我自己的判断。
第十三号缺陷,最直白的一个
第十三号缺陷是这批里最直白的:main() 没有办法通过进程退出码来报告失败。无论里面什么环节失败,进程最终都以状态 0 结束。唯一能让失败逃逸出来的方式,是一个未处理异常意外泄漏出去。
我为它写的测试,开头有一段文档字符串,用自己的话说明了修复必须达到什么效果:一旦修复完成,失败路径上至少存在一种产生非零退出码的手段,比如 sys.exit(1)。
而测试实际断言的是:
- 存在 import sys
- 存在对 sys.exit(...) 的调用
断言的是“存在”,不是“非零”。文档字符串和断言是两个不同的规格说明,而我在同一次编写里,相隔十行把它们写了出来。
模型提交了一个永远返回0的补丁
模型返回的补丁是这样的:在 audit.py 里加上 import sys,然后在 main() 之后追加 sys.exit(0)。sys.exit(0) 永远以零退出,它不可能报告失败——而这恰恰是缺陷的全部内容。模型甚至在随补丁一起返回的风险字段里标注了自己的不安,说它“可能掩盖意外异常”,但还是提交了。
我应用了这个补丁,跑了测试。绿色通过。
两个错误本该互为后盾,却朝着彼此失败
把这两个错误拆开看,都不值得大惊小怪。模型产出了一个肤浅的补丁:这种事经常发生,而这正是你需要测试的原因。测试断言了与它声明意图相邻的东西:这种事也会发生,而这正是你需要审查补丁的原因。
麻烦在于,每一个都本该是另一个的后盾,结果它们却朝着彼此的方向失败。双方都把“通过非零退出码报告失败”压缩成了“这附近应该有个 sys.exit”。这不是两颗骰子掷出同一个数字那种巧合。两边都在同样的完成压力下读着同一个英文句子,而对这个句子的肤浅解读是一个强吸引子。任何快速读它的人都会落到那里。
独立流程只有在你关心的那个轴向上真正独立,才会给你独立的错误。而我的两个流程共享了一个我未曾察觉的轴向。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.