返回探索
指南VibeFix 编辑部更新于 2026年10月2日

AI 生成代码的测试策略:从“能跑”到“敢上线”

演示完美、上线三天就炸的支付 webhook 事故:让 AI 写测试的四个正确姿势,三条必须人审的高压线(钱、权限、删数据 / 并发 / 迁移脚本),以及一套今晚就能搭起来的最小测试流水线。

概念封面:深色背景下发光护盾与对勾悬于代码流之上

AI 写代码,"能跑"太容易了。你描述需求,它吐出代码,你点几下,通了——多巴胺拉满。但"敢上线"是另一回事:半夜三点被报警短信吵醒时,你会发现,AI 生成的代码最危险的地方,恰恰是它"看起来没问题"的地方。它从不疲倦,也从不怀疑自己;它写的 bug,同样自信满满。

这篇文章不贩卖焦虑,只给方法:先讲一个"演示完美、上线三天就炸"的真实事故,再讲让 AI 写测试的正确姿势(姿势错了,测试写得越多越心安,错得越离谱),然后划出"哪些测试必须人审"的三条高压线,最后给一套今晚就能搭起来的最小测试流水线。目标:把"能跑"的运气,换成"敢上线"的确定性。

先讲个事故:演示时完美,上线第三天炸了

独立开发者老周(化名)用 AI 做了一个知识付费小站,核心链路是"用户付费→Stripe 回调→开通权限→发邮件"。上线前他亲自点了 5 遍完整流程:付钱、到账、开课、收邮件,全通。演示给朋友看时,所有人都说"稳了"。上线第三天,凌晨两点,他被短信轰炸醒:20 多个用户重复收到了开通邮件,有 3 个人被重复扣了款。

根因复盘,堪称 AI 生成代码的典型事故模板:Stripe 的 webhook 有重试机制——第一次回调处理稍慢,Stripe 就再发一次、再发一次。AI 生成的回调处理函数里,没有做幂等校验:来一次请求,开一次课、发一封邮件、记一笔账。老周手动点的 5 遍,每次都是"干净"的单次请求,永远测不出重试风暴。而 AI 在写这段代码时,根本没写"失败路径"的测试——它的测试用例全是"正常付费一次,断言开通成功",happy path 全绿。

这次事故赔了 4000 多块退款和道歉红包。老周的总结一针见血:"我让 AI 写了代码,又让 AI 写了测试,等于让考生自己出卷、自己判分——满分是必然的,及格是偶然的。"从那天起,他立了一条铁律:AI 可以写测试,但"测试在测什么",必须人说了算。

为什么 AI 特别容易漏掉失败路径?三个原因:第一,训练语料的幸存者偏差。开源代码库里的测试,happy path 本来就占多数,AI 学到的"测试长这样",自然也是多数 happy path。第二,AI 没有"被凌晨叫醒"的恐惧。人类程序员写幂等、写重试,是因为被坑过;AI 没被坑过,它不知道疼。第三,你的提示词没要求。"写个支付回调"是功能描述,不是质量描述——你不提失败路径,AI 默认你不关心。所以,失败路径的测试,永远是你(而不是 AI)要主动索取的东西。

让 AI 写测试的正确姿势

先纠正一个误区:让 AI 写测试本身没错,错的是姿势。四个正确姿势:

  • 姿势一:测试即规格,先写断言再写实现。不要等代码写完再让 AI "补测试"——那时 AI 只会顺着已有实现写"恰好通过"的断言。正确顺序是:你先把验收标准写成自然语言("同一笔订单重复回调,只能开通一次"),让 AI 把它翻译成测试用例,先运行,看它变红,再让 AI 写实现把它变绿。测试在这里的角色不是"验证代码",而是"锁定规格"。规格一旦被测试锁定,AI 后续的重构就不敢乱发挥。
  • 姿势二:给 AI"反例种子",让它去扩散。AI 不擅长"凭空想出刁钻的边界情况",但非常擅长"顺着例子发散"。你列出 5 个你能想到的反例(空字符串、负数、超长输入、并发重复请求、时区边界),然后指令:"针对每个反例生成测试,并再发散出 10 个同类边界情况。"实测下来,AI 发散出的边界情况里,约三成是你没想到的——而这三成,往往就是线上事故的来源。
  • 姿势三:用属性测试代替"举例测试"。传统测试是"举例":输入 A,期望输出 B。AI 写的举例测试有个致命倾向——例子总是挑"最顺"的那个。属性测试(property-based testing)反过来:定义"对任意输入都成立"的规则(比如"序列化再反序列化必须等于原文""排序结果必须是有序的"),让框架自动生成上千个随机输入去撞。对于 AI 生成的解析、转换、计算类代码,属性测试的 bug 检出率远高于举例测试。让 AI 帮你写属性和生成器,正好发挥它"不知疲倦"的长处。
  • 姿势四:覆盖率是参考,不是目标。行覆盖率 90% 听起来很美,但 AI 生成的代码达到 90% 覆盖率太容易了——它会顺手生成大量"调一下、断言个 true"的注水测试。真正要盯的是分支覆盖里"没跑到的失败分支":catch 块、重试逻辑、降级路径、幂等判断——这些恰恰是线上事故的高发区。要求 AI 在测试报告里单独列出"未覆盖的异常分支",你逐条决定:是补测试,还是确认"这条分支确实不可能发生"。
  • 姿势五:突变测试——让 AI 自己"使坏"。代码生成后,再开一个任务:"故意把这段代码改坏 10 处(改错条件、删掉判空、写反比较),看现有测试能不能抓住。"抓不住的"坏",就是测试的盲区。突变测试是检验"测试质量"的测试,特别适合 AI 生成的代码——因为 AI 写测试时"顺着实现走"的倾向,会让盲区系统性地存在。每月跑一次,盲区会越来越少。

姿势之外,还有个心态:把"测试红了"当成好消息。很多人看到 AI 生成的测试变红就慌,觉得"AI 写错了"。错——测试变红,是它在帮你"提前"发现实现的问题:红在开发机,总比红在生产环境强。练出"先红后绿"的肌肉记忆,是 vibe coder 从"玩具"走向"工程"的成人礼。

哪些测试必须人审:三条高压线

AI 写测试,人审测试——但人的精力有限,必须把评审火力集中在最高危的地方。三条高压线,碰到任何一条,测试用例必须逐行人审:

  • 高压线一:钱、权限、删数据。凡是涉及资金流动(支付、退款、计费)、权限变更(提权、分享、公开)、数据删除(软删除都不行)的代码,其测试的每一个断言都必须人审。审什么?审"断言在测什么":assertEqual(balance, 100) 是在测"扣对了钱",还是在测"代码跑通了"?AI 最爱写"自嗨式断言"——比如先调接口拿到结果,再断言结果等于刚才拿到的结果(assertEqual(result, result) 的各种变体),这种测试永远全绿,毫无价值。高压线代码的测试,必须由人确认"每个断言都对应一条真实业务规则"。
  • 高压线二:并发与竞态。AI 写单线程逻辑很强,写并发一塌糊涂——因为它训练语料里"正确处理并发"的样本本来就少。凡是涉及"同时""重复""超时重试"的场景(秒杀库存扣减、 webhook 幂等、分布式锁),必须人审测试是否真的构造了并发场景:有没有用多线程/多进程去撞?有没有模拟重试风暴?老周的事故如果当时有人审一眼测试用例列表,看到"无并发测试"五个字,悲剧就不会发生。
  • 高压线三:数据迁移脚本。迁移脚本的特点是"只能跑一次、跑错无法回头"。AI 生成的迁移脚本,测试必须包含: dry-run 模式(只打印 SQL 不执行)、回滚脚本、以及"在生产数据快照的拷贝上跑一遍"的记录。这一条没有商量余地——没经过人审的迁移脚本,不许碰生产库,这是铁律。

高压线之外,还有一条通用审法:看 AI 的测试里有没有"反例"。一个只有 happy path 的测试文件,等于没测。快速判断标准:测试文件里"异常""边界""并发"三类用例加起来不到 30%,打回重写。

审断言时,记住"三问":一问:这个断言失败时,我能定位到哪个业务规则坏了?如果失败信息是"expected true but was false",等于没说——好的断言自带业务语义。二问:把实现删掉,这个测试会红吗?把被测代码注释掉再跑一遍,还绿的测试可以直接删了。三问:这个测试有"反例兄弟"吗?每个 happy path 断言旁边,有没有对应的异常或边界断言?没有就是裸奔。三问答不上来,打回。

再补一个冷知识:AI 写的测试,第一次运行的通过率通常高得反常——接近 100%。别被这个数字迷惑:它恰恰说明测试和实现出自"同一个脑子",盲区完全重合。健康的信号是:测试第一次跑,红 20% 到 30%,然后修实现变绿。全绿的测试套件,等于没测。下次看到全绿,先怀疑,再庆祝——全绿是最需要警惕的颜色。

一套今晚就能搭起来的最小测试流水线

道理都懂,落地最难。下面这套流水线是"最小可用",个人项目今晚就能搭完:

  • 第一步:给 AI 立规矩——"无测试不合并"。在项目的 AGENTS.md(或等效的 agent 指令文件)里加一条:任何 AI 生成的 PR,必须附带测试用例,且测试必须先红后绿(先写断言、看红、再实现、看绿)。把这条写进 agent 的"出厂设置",比每次口头要求可靠一百倍。
  • 第二步:pre-commit 本地跑单测,2 分钟内必须跑完。用 git hook 在提交前自动跑单元测试。关键约束是"快":超过 2 分钟,人就会想办法绕过它。跑得慢的集成测试挪到 CI 里,本地只跑单测。AI 生成的代码,必须先过这一关才能进仓库。
  • 第三步:staging 环境用"影子流量"跑一遍。把生产环境的真实请求复制一份到 staging(脱敏后),让 AI 生成的新代码在影子流量下跑 24 小时。老周的 webhook 事故,在影子流量下 10 分钟就会暴露——真实世界的重试风暴,本地永远模拟不出来。
  • 第四步:每月一次,让 AI 红队攻击自己的代码。开一个新会话,给 AI 充分的"攻击者"人设:"你是安全研究员,这段代码是你的目标,找出所有可利用的漏洞并写出 PoC 测试。"AI 找自己(或别的 AI 写的)代码的 bug,出奇地有效——因为它不受"我写的代码没问题"的心理防御影响。每月一次,半小时,经常有惊喜(惊吓)。
  • 第五步:建立"测试坏味道"清单,贴在墙上。让 AI 帮你整理一份:sleep(1000) 式硬等待、assertTrue(true)、测试间共享全局状态、用随机数却不设种子、一个测试方法里断言 20 个东西……每次 review 测试,先过一遍坏味道清单。坏味道不是 bug,但它是 bug 的温床——AI 生成代码的坏味道尤其多,因为它"看起来"都写对了。

我的观点:测试不是不信任 AI,是把运气换成确定性。

有人觉得,给 AI 生成的代码写测试是"不信任 AI"的表现。恰恰相反——正因为信任 AI 的产出速度,才更需要测试来守住质量下限。没有测试的 AI 开发,是在用"演示时的运气"赌"上线后的确定性",赌赢的概率随着代码量增加指数级下降。

更深一层:测试是人与 AI 之间最清晰的分工界面。AI 负责"不知疲倦地生成"——代码、测试用例、边界发散;人负责"不可外包的判断"——这个断言在测什么、这条高压线能不能过、这个失败分支接不接受。老周事故之后说:"以前我觉得 review 是负担,现在我明白了:review 断言,是 vibe coding 时代程序员最后的、也是最重要的手艺。"

最后说个反常识的:测试写得最多的团队,往往不是最慢的,而是最敢重构的。AI 时代重构会极其频繁(模型升级、prompt 调整、架构推翻重来),没有测试兜底,你不敢让 AI 动旧代码,代码就烂在那里。测试不是成本,是你未来每一次"让 AI 大改"的底气。

所以,别再问"AI 写的代码要不要测试"了——要。但换个问法,答案更有价值:"我的测试里,有多少断言是我亲手确认过'在测对的东西'的?"这个数字,就是你的代码"敢上线"的程度。今晚就从给你的核心链路补三条反例测试开始。

浏览项目广场发布你的项目

相关文章

深色错误监控仪表盘界面,象征 vibe 项目的错误追踪与崩溃上报体系
指南
上线第一天用户白屏了你却最后一个知道:vibe 项目的错误监控与崩溃上报实战

每个 vibe 项目都会经历同一个黑色幽默时刻:网站白屏了,朋友比你的监控先告诉你。这篇实战为一人团队搭建完整错误监控体系:5 分钟 Sentry 最小闭环、错误边界、上报上下文设计、后端结构化日志、AI 调用专项防护、告警分级降噪,最后附上线检查清单。

调试排错后端工程部署上线