首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >AI写码太快,传统测试扛不住了——Meta的JiTTesting把测试从固定资产变成一次性探针

AI写码太快,传统测试扛不住了——Meta的JiTTesting把测试从固定资产变成一次性探针

作者头像
乔梁-北京
发布2026-09-16 21:40:14
发布2026-09-16 21:40:14
1150
举报

 你有没有遇到过这种情况:AI 编程工具几分钟改完一堆代码,看起来挺靠谱,但心里总不踏实——测试套件全绿,可你知道,那些测试是改之前写的,根本没覆盖这次改动。

最近 Meta 发了一篇论文,讲 JiTTesting(Just-in-Time Catching Test Generation),我觉得思路很值得分享。核心做法是:每次 PR 提交时,让 LLM 临时锻造一套测试,专门抓『这次 diff 刚引入的行为差异』,抓完就退场。不取代你现有的测试,而是在它上面加一道动态防线。

1 为什么:AI 写码太快,传统测试扛不住了

当 Agent 和 Copilot 成为日常开发工具,传统测试体系有三个问题越来越明显:

1. 维护成本爆炸

AI 提交的 diff 又大又频繁,人提前写的单元测试第二天就过时。如果每一条 AI 生成的用例都当永久资产维护,人力成本根本扛不住。脆断断言满天飞,维护倒比写代码还累。

2. 传统加固测试「只守未来,不抓当下」

Hardening Test(加固测试)的设计目标是:生成时通过 → 入库 → 长期防回归。它天然对『本次 diff 刚引入的行为变更』不敏感——旧套件全绿,不代表新代码没埋雷。它设计出来就不是干这个活的。

3. 全量补静态测试不划算

AI 产量越高,静态套件越容易脆断。而且那些埋得深的逻辑变更,常规功能测试未必能揪出来。你花大力气补了一堆测试,结果发现覆盖率上去了,但真正该抓的 bug 一个没抓到。

核心矛盾很简单:代码变更速度远大于人类写测试的速度,而且传统测试默认『代码是对的』,不会主动去找当前 diff 里的意外行为差异。

2 解决思路:测试分两类,临时线「按需造、双版比、可收割」

JiTTesting 的核心反转是:把测试从『统一当固定资产』拆成两条线,并存,互不替代。

Hardening Test(永久资产)

Catching Test(临时探针)

目的

防未来回归

抓本次 diff 的行为差异

生命周期

入库,长期维护

默认不入库,用完即弃

通过条件

生成时通过

设计上期望在 diff 上失败

关键概念是 Weak Catch 和 Strong Catch。同一测试在旧版本 parent 上通过、在新版本 diff 上失败,这叫 Weak Catch(弱捕获),只说明两边行为不一样。再经过通用预言判断:如果这个失败确实是 bug → Strong Catch(强捕获/真阳性);如果只是测试本身较真或是预期内的变更 → 假阳性。

还有个容易误解的点:Passing Test 可以「收割」为永久资产

Catching 流程里,LLM 生成的测试会在 parent 和 diff 上各跑一遍。那些在两个版本上都通过的测试,说明它不是专为制造失败而写的,而是正常覆盖了行为。这类测试进入 passing 池,列为 Hardening Candidate(候选加固测试),经人工评审稳定性、长期价值、维护成本后,值得的才固化入库。不是 parent 通过就自动入库,但也不是全部丢弃。

永久 Hardening 资产继续存在;每次 PR 额外由 LLM 锻造一套一次性 Catching 探针抓差异,抓完就退场,只把少量顺手写得好、覆盖有价值的 passing 测试评审后转永久。

3 用什么工具、按什么步骤解决

核心组件

Dodgy Diff 管线(铺量型) 不猜意图,把 diff 直接当『嫌疑变异体』,LLM 生成测试来区分 parent 和 diff 的行为。简单粗暴,覆盖广,但误报也多。

Intent-Aware 管线(精准型) LLM 先读 diff 标题、描述、代码 → 推断业务意图 → 列出风险点(空值、边界、状态机)→ 在 parent 上注入变异(比如把 >= 500 改成 > 500、注入 return null、条件取反等 6 类标签)→ 生成『parent 过、mutant 挂』的测试 → 再拿去跑真实 diff。

Meta 的实测数据挺有意思:Intent 管线生成 811 条测试,52 个 weak catch(率 6.4%),覆盖 7.9% 的被测 diff;Dodgy 生成 1621 条,41 个 weak catch(率 2.5%),覆盖 4.0%。Intent 的捕获率大约是 Dodgy 的 2.6 倍。

RubFake 规则评估器(确定性信号层) 识别 14 类误报模式(布尔翻转、mock 错误、反射断裂等)和 26 类风险标记(扫描执行结果与代码片段),标记可疑度,但不单独定论。

LLM-as-Judge 集成(语义评分层) 多模型输出风险概率分(-1 到 +1)加等级加文字理由,聚合排序,减少人工评审量。

Human-in-the-Loop(最后一道关) 只给工程师发一句是非题——『这个行为变化是你预期的吗?』预期内点 dismiss,非预期就修代码。不让人读测试代码,几秒钟完事。

执行步骤(PR 提交触发,自动跑)

第 1 步:环境隔离。CI 拉出 parent(master 基线)和 diff(待提交版本)两套工作副本,测试跑独立子进程,避免 APM 探针或自定义 ClassLoader 污染。

第 2 步:Diff 解析。提取变更函数/类,过滤无关文件,输出结构化 diff 摘要,喂给后续两条管线。

第 3 步:双管线并行生成。Dodgy 直接针对 diff 行为差异写测试;Intent 推意图 → 列 risks → 造 mutant → 生成『parent 过、mutant 挂』的测试。

第 4 步:双版本验收所有候选测试先跑 parent,必须全过(不过的说明测试本身有错,丢弃)。再把同一批测试跑 diff。仅『parent 过 + diff 挂』的留为 weak catch;parent 和 diff 都过的进入 passing 池,作为 hardening candidate 候选。

第 5 步:降噪排序RubFake 打确定性规则信号 → LLM 集成打语义分 → 合起来排优先级,只把高分 weak catch 推给人审。

第 6 步:人审触达。工程师收到类似『布尔值从 true 变 false 是否预期』的提问,几秒到几分钟可完成 dismiss。Catching 测试本身默认不入库,不用担心测试垃圾堆积。

第 7 步:选择性收割。Passing 池里断言稳定、覆盖有价值、维护成本可控的,人工评审后转为 Hardening Test 正式入库。当前工程实现默认只留归档目录,不自动 push。

落地节奏建议

从 0 到 1 分四阶段推进:先选一个项目跑 Dodgy 管线看 weak-catch 率和单次成本;再铺自己项目的 RubFake 规则库校准误杀率;接着接入单模型语义评分,确认互补后升级多模型集成;最后上 Intent 三侧矩阵(parent/mutant/diff),并把 passing test 的收割流程跑通。别一上来就追求全自动入库。

4 本质

JiTTesting 给传统测试体系补了一条按 diff 定制的动态防线。AI 写码越快,这条防线越值钱——但它不取代永久测试资产,而是让『临时探针』和『永久加固』各司其职。

在 AI 写代码越来越快的今天,这个思路挺值得工程团队认真考虑一下。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-09-09,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 1 为什么:AI 写码太快,传统测试扛不住了
  • 2 解决思路:测试分两类,临时线「按需造、双版比、可收割」
  • 3 用什么工具、按什么步骤解决
    • 核心组件
    • 执行步骤(PR 提交触发,自动跑)
    • 落地节奏建议
  • 4 本质
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档