多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

AI 生成的代码怎么测才敢上线?7 道自动化闸门清单

AI 生成的代码怎么测才敢上线?7 道自动化闸门清单 AI 生成的代码怎么测才敢上线7 道自动化闸门清单开头钩子AI 五分钟写完功能还顺手把测试也写了——全绿通过行覆盖率 92%。上线第二天线上静默崩溃。问题出在哪AI 在给自己的 bug 打分。01先别信绿勾覆盖率是个错觉让 AI 生成功能代码再让它补一下测试几分钟就能得到一片绿色对勾。但这正是最危险的地方同一个模型既写实现又写测试等于让 bug 自己给自己评卷。测试的期望值是从有缺陷的实现里推导出来的错误逻辑被原样固化进断言两边达成共识——这就是测试 AI 代码时要避开的验证悖论。这类测试通常有四个特征断言 mock 而不是系统本身同义反复、依赖被 stub 到测试跑在真空里、只测快乐路径、把函数当前返回的错误值直接抄进断言。最典型的反模式是测试验证的是 mock 的行为而不是你的业务逻辑。// 反模式测试的是 mock不是系统it(‘fetches user data’, () {const fetchMock jest.fn().mockReturnValue({ id: 1, name: ‘Alice’ });const result fetchMock();// 这一行断言的是 mock 工作正常与业务逻辑无关expect(result.name).toBe(‘Alice’);});把断言整行删掉测试照样通过——那它从头到尾就没验证过任何行为。高覆盖率只能证明代码跑过不能证明功能正确。为什么说覆盖率是错觉行覆盖率衡量的是哪些代码行被执行行为覆盖率衡量的是哪些业务结果被验证。AI 极其擅长前者把代码跑一遍、什么都不断言轻松刷到 90%。TestDino 的实测对比触目惊心行覆盖率 92%行为覆盖率只有 23%。图1 · 覆盖率错觉行覆盖率 92%行为覆盖率仅 23%示意图绿勾只能证明“代码跑过”不能证明“功能正确”数据源自 TestDino 实测02AI 的 bug 和人的 bug 不一样人的 bug 源于疲劳笔误、差一错误、用过时的 API。AI 的 bug 是流畅的错误——读起来完全合理却在边界条件上悄悄偏离意图。肉眼 review 前先认识这四类典型缺陷逻辑漂移主路径正确边界处推理与真实业务意图分叉。比如折扣判断写成 if (total 100)漏掉了 。自信的错误人类不确定时会犹豫、留注释AI 从不——错误代码和正确代码一样流畅自信。幻觉 API编造根本不存在的函数、导出或包。知名案例AI 自信地调用 React 里不存在的 useMetadata hook。上下文失明只看到当前文件忽略系统架构——假设数据库存在、鉴权已生效、队列已连接其实都没有。维度人类AI逻辑错误明显笔误、差一错误貌似合理边界处偏离业务逻辑API 用法用过时方法编造从未存在的函数安全偶尔硬编码系统性嵌入密钥和不安全默认值依赖用旧版本编造不存在的包供应链风险测试质量跳过边界用例写验证不了任何东西的同义反复测试图2 · AI 代码的 4 类典型缺陷示意图逻辑漂移 / 自信的错误 / 幻觉 API / 上下文失明肉眼 review 难以发现03人审之前先过安全扫描和静态分析肉眼 review 对付不了机器规模的错误。AI 从公开数据集学到的不仅是好代码还有大量不安全模式硬编码密钥、SQL 注入、XSS、不安全的反序列化、缺失鉴权。更隐蔽的是幻觉依赖AI 编造一个听起来很合理的包名攻击者注册同名包投毒直接变成供应链攻击入口。所以每个 AI 建议的依赖都要验证它真实存在且被维护。在人工评审之前先把三道自动关卡跑起来·密钥扫描gitleaks / GitHub Secret Scanning拦截提交到 main 的硬编码凭据·依赖扫描npm audit / Dependabot / Snyk核实包真实存在且无漏洞·SAST 静态分析SonarQube / Semgrep / CodeQL自动抓不安全模式与坏味道静态分析跑一次只要几秒、几乎零成本却能把大量测试根本够不着的缺陷挡在合并之前。把它当成流水线第一道质检站而不是让 review 的人肉去海里捞针。04打破验证悖论断言必须人来写怎么让测试真正独立于代码四个原则人拥有断言AI 可以写脚手架和 setup但最后一行期望值必须人来定。从规格生成测试让写测试的模型看需求单、产品文档而不是对着实现写。独立验证换一个工具、换一个作者写测试避免共享盲区。端到端兜底从系统外部以真实用户视角验证结果不依赖 mock。05变异测试唯一能证明测试有价值的办法测试到底有没有用只有一个可靠的检验方法故意把代码改错然后看测试会不会变红。手动就能做找一段被 AI 测试覆盖的函数把 翻成 或反转一个关键条件再跑一遍测试。如果测试依然通过——它什么都没证明立刻重写断言。function getDiscount(cartTotal) {// 变异体故意把 翻成 来破坏逻辑// 测试必须在这里失败才算有效if (cartTotal 100) return 10;return 0;}自动化工具能系统化地做这件事StrykerJS/TS/C#、PITJava/JVM、mutmutPython。关键模块变异分目标 60–70%。这个指标靠刷行覆盖率糊弄不过去是 AI 测试真正意义上的信任测试。06属性测试 真实 E2E补边界别只信 mockAI 优化的对象是训练数据里的常见模式边界条件被系统性跳过。属性测试换个思路不测具体例子测无论什么输入都必须成立的不变量用随机输入把输入空间炸一遍。import fc from ‘fast-check’;// 不变量排序后数组长度不变test(‘AI 排序函数保持数组长度’, () {fc.assert(fc.property(fc.array(fc.integer()), (arr) {const sorted aiGeneratedSort(arr); return sorted.length arr.length;}));});JS/TS 用 fast-checkPython 用 Hypothesis。和变异测试叠加就形成了 AI 几乎无法钻空子的验证层。单元测试全绿不代表生产不崩。AI 喜欢重度 mock数据库、队列、对象存储全被 stub 掉测试跑在真空里——本地全绿上线才发现真实表不存在。所以涉及数据库、鉴权的改动至少要有一条针对真实基础设施的测试再加系统边界的集成测试和完整用户流的 E2E。Playwright 是 E2E 的可靠选择但 AI 生成的 E2E 要改造把 .css-1x2y3z 这类脆弱选择器换成基于可见文本 / ARIA 角色的意图定位器断言记录真的保存了而不是页面加载了用 trace 区分测试真通过和应用碰巧工作不要用重试掩盖抖动。07抖动测试治理 CI 门禁AI 每周批量产出成百上千个测试抖动率会快速膨胀。一个偶尔没理由挂掉的测试套件会训练团队无视红色 CI。治理流程三步持续检测看多次运行的通过率分布而不是单次结果、准确分诊区分测试抖动和应用间歇性 bug、果断隔离确认抖动的测试移出关键路径。合并 AI 写的 PR 前建议把 7 道闸门全部自动化闸门抓什么工具密钥扫描硬编码密钥、凭据gitleaks、GitHub Secret Scanning依赖解析幻觉依赖、漏洞库npm audit、Dependabot、Snyk静态分析不安全模式、坏味道SonarQube、Semgrep、ESLint变异分阈值测不出注入缺陷的测试Stryker ≥60%仅改动文件抖动率分析新引入的测试不稳定flake 追踪工具行为覆盖率跑了但没断言结果的代码自定义断言审计E2E 验证mock 掩盖的集成失败Playwright 端到端套件一个提醒别用AI 检测工具当闸门——这类检测器误报率高得离谱要卡就卡可验证的正确性证据。图3 · 合并前必须通过的 7 道自动化闸门示意图安全扫描 → 静态分析 → 人类断言 → 变异测试 → 属性测试 → 真实 E2E → CI 门禁08真正值得盯的四个指标别只问测试过没过要问测试会不会发现功能坏了。盯这四个行为覆盖率验证了多少业务结果、变异分能不能察觉故意注入的缺陷、抖动率假阳性噪音占比、缺陷逃逸率AI 代码 vs 人类代码的生产缺陷占比。按来源分段统计就知道人工 review 的精力该花在哪。落地总结测试的价值不在于通过而在于有能力失败。绿勾只是起点——先扫安全、再破悖论、注入变异、补上边界、跑真 E2E最后用 CI 闸门锁死。这套纪律到位AI 编码才从快变成又快又稳。关注我们一起把技术讲明白寻码札记。
返回列表