Industry & PracticeResearch & Benchmarks
有 缺陷 的 代码 会 让 生成 的 测试 去 证明 缺陷 是 对 的
用有缺陷的代码提示大模型生成单元测试,模型会把错误行为当成预定功能。11 个模型上,误导测试平均从修复代码条件下的 0.46% 升到 3.84%,能发现缺陷的有效测试从 8.51% 降到 2.98%。把实现换成模型写出的行为规格,误导下降,有效测试上升。

In this piece
本文是论文 Evaluating and Mitigating the Misguidance Effect of Buggy Code in LLM-Generated Unit Tests(arXiv:2607.22883)正文第 1 节至第 8 节的中文译文,由智测团队翻译。参考文献未逐条展开。正文保留了缺陷分类、主表平均数字、序列分数、文档字符串抽查和无缺陷代码上的编译与覆盖变化。
摘要
大语言模型在自动生成单元测试上很有希望。近期研究提示:如果提示里放的是有缺陷的代码,生成测试的质量会变差。本文给出一个新指标,定量测量「误导效应」:有缺陷的代码把模型带向去验证错误行为的测试,而不是去暴露它。分析显示,用有缺陷的代码做提示有双重影响:显著增加断言错误行为的「误导测试」,同时压低能找出缺陷的有效测试。从模型内部看,有缺陷的代码也会把模型对候选测试的偏好扭向断言同一错误行为的那些测试。
为了对付这一点,作者提出并验证一种基于规格的方法:先让模型从被测代码写出行为规格(文档字符串),再在生成测试时只用这份规格,把有缺陷的实现从提示里拿掉。即便是简单的文档字符串,也能明显减轻误导并提高缺陷检测。加上基于推理的意图分析之后,效果更好,也能作为多轮交互式提示的更好起点。方法对有缺陷和无缺陷的代码都适用。用在无缺陷代码上时,编译失败、误报测试和覆盖率与直接用源码做提示相当。
1 引言
单元测试核对单个组件是否按预期行事。及早发现缺陷能降低维护成本、方便重构、提高可靠性。手工写测试费力且容易出错,因此有大量工作想把它自动化。
GPT、DeepSeek、Claude 等模型在代码任务上表现强,近期不少研究用它们自动生成单元测试。已有研究大多把无缺陷代码当作主要提示,并用测试正确性和覆盖率来评。这些指标并不直接反映生成测试发现缺陷的能力。这种实验设计也不像真实情况:被测代码常常是有缺陷的,这可能降低生成测试套件的效果。只有少量工作把有缺陷的代码当作输入。Abdullin 等人报告从有缺陷源码生成测试时的缺陷检测效果。Mathews 等人认为,有缺陷的代码会妨碍自动测试生成系统发现它自己。He 等人发现,在迭代的代码–测试生成里,上一轮有缺陷代码导出的测试可能强化代码里已有的毛病。这些研究既没有相对无缺陷输入量化性能下降,也没有确定下降从哪来。
Huang 等人试图定量测量有缺陷代码在生成单元测试时把模型带偏的程度,也就是让模型把错误行为当成预定功能,并生成去验证这种行为的测试。他们的指标有一个关键限制:把所有在有缺陷版本上通过的测试都标成「被误导」。实践里,有缺陷代码在很多输入上和无缺陷代码表现一样,只在触发缺陷的特定输入上不同。本文在第 2 节用经验说明:为有缺陷代码生成、并且在有缺陷版本上通过的测试,大多数在修复后的对应版本上也通过。因此 Huang 等人的指标没有准确抓住误导现象是否存在、有多大。
为准确量化,本文做大规模经验研究,用一个新指标明确测量「误导测试」:在有缺陷版本上通过、在无缺陷对应版本上失败的测试。图 1 用 Defects4J 里缺陷 Lang-14 的 StringUtils.equals 作例子。这个方法本应比较两个 CharSequence 的内容。CharSequence 是 Java 接口,String、StringBuilder 和 StringBuffer 都实现它。因此 "abc" 和 new StringBuilder("abc") 尽管具体类型不同,内容相同就应判等。无缺陷实现用 regionMatches 处理这种情况。有缺陷实现直接调用 cs1.equals(cs2)。String.equals 只有在参数也是内容相同的 String 时才返回真,拿 String 和 StringBuilder 比会错误地返回假。把这份有缺陷实现放进提示后,模型把错误行为当成预定行为,生成的测试去断言这个错误行为。
计算新指标时,作者使用真实有缺陷代码片段及其修复版本的平行数据,从而在预定功能相同的前提下,比较测试在两种版本上的结果。相对修复后的对应版本,用有缺陷代码做提示会显著增加误导测试,并压低有效测试,也就是能成功识别缺陷的测试。相关分析显示,误导测试的减少与有效测试的增加有强正相关。减轻误导,可能带来更有效的测试套件。文中没有给出具体的相关系数。
从模型内部验证时,作者分析序列分数。这是衡量模型对候选文本偏好的常用指标。有缺陷的输入代码把这种偏好扭向断言其错误行为的测试。这种损害也延伸到更高级的技术,会降低近期测试生成工作里常见的多轮、由反馈驱动的提示流水线。
作者认为,主流做法「用被测代码提示模型」有根本限制:代码若有缺陷,误导效应会把模型带向生成去断言本应被暴露的行为的测试。缓解办法来自基于规格的测试,也就是黑盒测试,测试驱动开发里广泛采用:测试从预定行为导出,而不是从实现导出。流程分两步。(1)用模型导出一份文档字符串,抓住预定功能,略去实现细节。(2)用这份文档字符串替换提示里的源码,从而去掉有缺陷实现这个误导来源。这个选择很关键:对有缺陷输入,必须把代码整个拿掉,而不是仅仅在旁边补充,才能有意义地减轻误导。这不同于先前只把模型生成的文档当作代码旁边的额外上下文。图 1 的同一例子里,文档字符串替换有缺陷代码之后,生成的测试正确断言 "abc" 和 new StringBuilder("abc") 应判等,从而暴露缺陷。即便简单的规格构造提示,也能明显得到更有效的测试套件。作者再用分析驱动的意图推导加强基线,得到更准确的规格,进一步减少误导测试、增加有效测试,同时不大增加那些断言「有缺陷版本和修复版本里都不存在」的幻觉行为的测试。这种方法也能增强近期工作采用的交互式多轮测试生成。作者还人工检查生成文档字符串的质量,并量化它对测试的影响:方法能有效挡住缺陷传播进文档字符串,并为一大部分有缺陷的焦点方法恢复正确行为。前者显著减少误导测试套件,后者贡献大量被发现的缺陷。
最后,实践里往往不知道被测代码是不是真有缺陷。作者表明方法可以同时用在有缺陷和无缺陷代码上。用在无缺陷代码上时,编译失败、误报测试(在正确代码上失败的测试)和测试覆盖,与直接用源码做提示的基线相当。不给开发者增加额外负担,生成的测试仍可用于回归测试等更广用途。
贡献有三条。第一,大规模定量研究,用新指标经验验证有缺陷代码的误导效应,并从模型内部确认;相关分析显示,减轻误导与提高生成测试的有效性有强正相关。第二,提出并评测基于规格的测试生成:提示的核心是模型生成的行为规格,而不是有缺陷代码。它显著减少误导测试,并提高缺陷检测率;也能增强交互式多轮提示,作者还分析规格质量如何影响最终测试套件。第三,方法对有缺陷和无缺陷代码都稳健。用在无缺陷代码上时,编译失败、误报测试和覆盖与基线相当。
2 研究设计
2.1 研究问题
RQ1:有缺陷代码的误导效应如何影响大模型生成的单元测试?
RQ2:所提出的基于规格的单元测试生成流水线,如何减轻误导效应?
RQ3:这条流水线是否影响从无缺陷代码生成的单元测试?
RQ1 查误导效应是否存在、有多严重,并验证它对缺陷检测的损害,再从模型内部确认,并分析减轻该效应与提高缺陷检测之间的相关。RQ2 在有缺陷代码上评流水线:能否减轻误导、提高缺陷检测,收益是否随规格质量上升,以及在多轮反馈提示里是否仍然存在。最后人工检查缺陷有没有被继承进模型生成的规格。RQ3 在无缺陷代码上评影响,确认不会给开发者增加不必要的负担,也不损害回归测试等更广用途。
2.2 基准
使用 Defects4J,一个含开源 Java 项目真实缺陷的常用数据集,例如 JFreeChart、Commons Lang。3.0 版含 17 个项目、854 个缺陷。每个缺陷都有有缺陷版本和修复版本,可能包含一个或多个有缺陷的方法,称为焦点方法。也提供人工编写的测试,包括能发现有缺陷焦点方法的那些。
沿用先前评测大模型单元测试生成的做法,测试生成和评测聚焦焦点方法。选择标准进一步收紧。(1)纳入全部非私有方法(public、protected 和默认可见性),因为从测试包可以访问,能直接测。(2)焦点方法必须在有缺陷版本和修复版本里都存在,补丁删除或新引入的方法排除。(3)只保留其有缺陷版本至少触发 Defects4J 里一条已有人工测试的焦点方法,从而保证对应补丁是修缺陷,而不是风格或性能优化。最终基准含 318 个焦点方法,覆盖全部 17 个项目里的 233 个缺陷。
2.3 测试生成工作流
工作流贴近 Yang 等人提出的、评测大模型生成单元测试的端到端流水线,包括构造提示和抽出单元测试。按他们关于有效提示上下文的发现,焦点方法之外再补上容易取得的周围代码:方法签名和参数、所在类的构造器、声明的字段、同类的其他方法。若参数类型或返回类型是用户定义的类,也加入这些类的构造器,使模型能实例化对象依赖。按实验设置,提示的核心行为输入是焦点方法体,和/或从焦点方法生成的文档字符串。系统指令把模型定位成专业 Java 开发者,并明确要求为所给代码生成单元测试。图 2 的提示大意是:你是编写 Java 测试方法的专业人员;下面给出被测代码和/或模型生成的文档字符串,以及与焦点方法相关的其他上下文;请用 Java 11 和 JUnit 4 写一些单元测试,尽量同时提高分支覆盖和行覆盖;输出格式为 Markdown,不需要解释。
采用这套提示配置有三个理由。他们评过一批开源和闭源模型,提示设计有一定一般性。他们的消融系统分析了额外代码上下文的影响,说明了本文纳入哪些上下文特征。所需上下文可以只从被测代码抽出,不必人工检查,从而全自动构造提示和生成测试,符合减轻开发者负担的目标。
从模型输出抽测试时,用 Tree-sitter 做抽象语法树解析,识别测试用例以及导入、辅助函数等。再与项目专用依赖,以及一套常见的 JDK(例如 java.util)和 JUnit(例如 org.junit.Assert)依赖合在一起,避免因缺导入而编译失败。
2.4 模型
为求分析全面,从六家开发者选了 11 个当时的前沿模型,在有的地方同时包含基础模型和推理模型。推理模型针对多步推理优化,常借助显式的思维链。基础模型直接生成输出。对能在两种模式间切换的混合模型,例如 Claude 4 Sonnet,分别评开启和关闭推理。表 1 如下。
| 开发者 | 模型 | 类型 | 是否开源 |
|---|---|---|---|
| Gemini 2.5 Pro | 推理 | 否 | |
| Gemini 2.5 Flash | 混合 | 否 | |
| Anthropic | Claude 4 Sonnet | 混合 | 否 |
| xAI | Grok-4 | 推理 | 否 |
| xAI | Grok-3 | 基础 | 否 |
| OpenAI | GPT-4.1 | 基础 | 否 |
| OpenAI | GPT-O4-mini | 推理 | 否 |
| DeepSeek | DeepSeek-V3 | 基础 | 是 |
| DeepSeek | DeepSeek-R1 | 推理 | 是 |
| Alibaba | Qwen3-Coder-Plus | 基础 | 是 |
| Alibaba | Qwen3-Plus | 推理 | 是 |
Gemini 2.5 Flash 和 Claude 4 Sonnet 各有开启推理的设置,后文标为 Reason。
2.5 缓解方法与基线
先前研究探索过用高质量的人工文档改进模型生成的测试,但实践里这种文档常常没有。本文改为让模型恢复被测代码的预定行为,并把测试生成集中在预定行为上,而不是可能错误的实现细节。
两步。第一,提示模型把代码的行为规格写成文档字符串。第二,把这份规格文档字符串当作测试生成模型唯一的行为输入,丢掉原来的有缺陷实现。相对直接用代码生成测试,主要额外开销是多一次生成文档字符串的模型调用,以及相应的输入输出词元。这不同于两类先前做法:只把有缺陷代码当作唯一输入,或只把模型生成的文档当作有缺陷代码旁边的补充上下文。比较的基线包括这些设置,以及同时去掉被测代码和生成文档字符串的设置,用来判断设计的两部分是否都必要:完全去掉被测代码,以及用模型生成的规格替换它。
基础文档字符串提示的大意是:请识别下面方法的意图和功能;请给出正式文档字符串,识别给定方法的功能和意图;避免直接引用焦点方法的代码,因为它可能有缺陷;只输出文档字符串。
高级提示在写文档字符串之前做两部分分析。(1)逻辑错误:实现是否与从方法名和上下文推出的意图矛盾,即便在正常路径上也会得出错误结果。(2)稳健性遗漏:生产质量代码本应有、但缺失的步骤,例如空值检查、边界条件、错误处理、必要的数据清洗或转义。推理模型只要被要求分析这些即可。基础模型不会可靠地走出所需推理,因此要求它明确报告发现的缺陷和所需修复,再在假定这些修复已经应用的前提下写文档字符串。高级提示与两个基线比较:基础文档字符串提示,以及带同样高级分析指令、但仍直接基于代码、不拿掉有缺陷实现的单步测试生成。后一个比较用来看:有缺陷代码仍然可见时,单靠高级分析能不能减轻误导。
最后,人工检查用高级文档字符串提示生成的全部 636 份文档字符串,来自应用本方法后、误导测试套件减少最多和最少的两个模型。用来分析文档字符串质量如何影响下游测试生成。
2.6 指标
评测把 Defects4J 的修复版本当作预定程序行为的黄金标准,并据此给所有测试贴标签。对相同输入,若某个实现产生的外部可观察输出与修复版本不同,在本评测里就不算无缺陷。表 2 按两个版本上的结果给测试分类。「阳性」表示标出了缺陷,「阴性」表示没有标出。
| 类别 | 修复版本 | 有缺陷版本 |
|---|---|---|
| 真阴性 | 通过 | 通过 |
| 真阳性(有效) | 通过 | 失败 |
| 假阴性(误导) | 失败 | 通过 |
| 假阳性 | 失败 | 失败 |
误导只计假阴性:在有缺陷版本上通过、在修复版本上失败。只有这些测试明确断言了有缺陷的行为。Huang 等人把所有在有缺陷版本上通过的测试(真阴性加假阴性)都当成误导的证据。表 3 说明这个合计主要被真阴性驱动。在有缺陷代码上通过的测试里,绝大多数、平均超过 90% 其实是真阴性,两边都通过。例如 Gemini 2.5 Pro 在有缺陷版本上通过 2,183 个,其中真阴性 2,010 个(92.08%),假阴性 173 个(7.92%)。Qwen3-Coder-Plus 的真阴性占 96.10%,假阴性只占 3.90%。表中假阴性比例最高的是 Qwen3-Plus,8.20%。因此用「在有缺陷版本上通过」的合计来当误导指标,并不能准确反映误导。
RQ3 测量测试正确性,包括编译失败率和误报率。误报测试是在无缺陷代码上失败、断言了该代码里并不存在的幻觉行为的测试。也测量无缺陷代码上的行覆盖和分支覆盖。
3 RQ1:有缺陷代码的误导效应
工作流见图 5:对每个焦点方法,分别从有缺陷版本和修复版本生成测试,再在两个版本上执行,分类后测量误导效应。
3.1 对测试生成的影响
表 4 比较从有缺陷代码和从修复代码生成的测试。用有缺陷代码做提示时,模型产生明显更多的误导测试:在有缺陷代码上通过,在修复版本上失败,从而错误地确认了有缺陷的行为。平均每个模型产生 137.69 个误导测试(3.84%)。换成对应的修复代码,平均降到 16.46 个(0.46%)。这个差距定量说明误导效应存在,而且不小:现代大模型会把错误逻辑理解成预定功能。
表 4 列出每个模型的测试总数,以及误导测试和有效测试的个数与百分比。上半是基础模型,下半是推理模型。
| 模型 | 有缺陷输入的测试数 | 误导数 | 误导比例 | 有效数 | 有效比例 | 修复输入的测试数 | 误导数 | 误导比例 | 有效数 | 有效比例 |
|---|---|---|---|---|---|---|---|---|---|---|
| Gemini 2.5 Flash | 3539 | 114 | 3.22% | 140 | 3.96% | 3616 | 11 | 0.30% | 279 | 7.72% |
| Claude 4 Sonnet | 4202 | 149 | 3.55% | 88 | 2.09% | 4250 | 15 | 0.35% | 361 | 8.49% |
| Grok-3 | 2543 | 71 | 2.79% | 93 | 3.66% | 2581 | 17 | 0.66% | 199 | 7.71% |
| GPT-4.1 | 2841 | 92 | 3.24% | 86 | 3.03% | 2905 | 11 | 0.38% | 236 | 8.12% |
| DeepSeek-V3 | 3002 | 76 | 2.53% | 113 | 3.76% | 3008 | 19 | 0.63% | 241 | 8.01% |
| Qwen3-Coder-Plus | 3455 | 80 | 2.32% | 157 | 4.54% | 3353 | 10 | 0.30% | 259 | 7.72% |
| 基础模型平均 | 3263.67 | 97.00 | 2.94% | 112.83 | 3.51% | 3285.50 | 13.83 | 0.44% | 262.50 | 7.96% |
| Gemini 2.5 Pro | 3284 | 173 | 5.27% | 98 | 2.98% | 3286 | 17 | 0.52% | 354 | 10.77% |
| Gemini 2.5 Flash(推理) | 3957 | 155 | 3.92% | 99 | 2.50% | 3956 | 7 | 0.18% | 293 | 7.41% |
| Claude 4 Sonnet(推理) | 4515 | 187 | 4.14% | 88 | 1.95% | 4553 | 27 | 0.59% | 372 | 8.17% |
| Grok-4 | 3923 | 179 | 4.56% | 145 | 3.70% | 3985 | 19 | 0.48% | 398 | 9.99% |
| GPT-O4-mini | 2500 | 130 | 5.20% | 36 | 1.44% | 2606 | 7 | 0.27% | 248 | 9.52% |
| DeepSeek-R1 | 3413 | 145 | 4.25% | 97 | 2.84% | 3622 | 21 | 0.58% | 324 | 8.95% |
| Qwen3-Plus | 4857 | 239 | 4.92% | 114 | 2.35% | 4808 | 33 | 0.69% | 389 | 8.09% |
| 推理模型平均 | 3778.43 | 172.57 | 4.61% | 96.71 | 2.54% | 3830.86 | 18.71 | 0.47% | 339.71 | 8.99% |
| 总平均 | 3540.85 | 137.69 | 3.84% | 104.15 | 2.98% | 3579.15 | 16.46 | 0.46% | 304.08 | 8.51% |
误导之外,缺陷检测也被直接削弱。有效测试在有缺陷代码上失败、在修复版本上通过。用有缺陷代码做提示时,平均只有 104.15 个(2.98%)。用对应的修复代码时,升到 304.08 个(8.51%),接近三倍。有缺陷输入不但带来更多不正确的测试,也压低有用的、能找缺陷的测试。
真实场景里,生成测试时并没有修复版本可用。从修复代码生成的测试表现更好,不是实用基线,而是一个预言,用来表明性能下降是有缺陷代码本身造成的。有缺陷代码是有效测试生成的主要障碍。一个关键含义是:先前只用无缺陷代码评测大模型测试生成的工作,很可能高估了这些模型真正的缺陷检测能力。
3.2 序列分数
序列分数反映模型对某个输出的概率偏好。若输入里的缺陷扭曲了生成偏好,那么在以有缺陷代码为条件时,误导测试应得到更高的序列分数;在以修复代码为条件时,有效测试应更高。
专有模型的接口拿不到序列分数,因此用三个开源模型当评估器:DeepSeek-V3、Qwen3-Coder-Plus、GPT-OSS-120B。为避免偏向自己的生成风格,采用交叉打分:每个模型只给其他开发者的模型所生成的测试打分。
表 5 的结果确认,有缺陷源码把生成偏好扭向断言有缺陷行为的误导测试。两条趋势一致。第一,误导测试在以有缺陷代码为条件时,平均序列分数高于以修复代码为条件。以 DeepSeek-V3 为评估器,从有缺陷输入换到修复输入,平均从 −1.21 降到 −1.31。Qwen3-Coder-Plus 从 −1.59 到 −1.75,GPT-OSS-120B 从 −2.29 到 −2.43。反过来,有效测试在以修复代码为条件时分数更高。DeepSeek-V3 从 −1.30 升到 −1.23,Qwen3-Coder-Plus 从 −1.75 到 −1.64,GPT-OSS-120B 从 −2.50 到 −2.42。这些行为差异来自模型在内部被有缺陷实现误导。分数为负是对数概率尺度上的常见写法,比较的是相对高低,不是绝对「好坏分」。
4 RQ2:用基于规格的方法减轻误导
表 6 比较四种输入下的误导测试(M)和有效测试(E):只有从有缺陷代码生成的文档字符串(本文方法)、只有有缺陷代码、既无代码也无文档字符串、文档字符串加上有缺陷代码。
相对「只有代码」,本文方法显著提高测试质量:全部模型平均的误导测试从 137.69 降到 113.00,少 24.69 个(−1.15 个百分点)。缺陷检测也明显提高:有效测试平均从 104.15 增到 186.77,多 82.62 个(+1.52 个百分点)。把模型的注意力放在规格上而不是有缺陷代码上,能减轻误导,并得到更有用的找缺陷测试。
「文档字符串加上代码」明显不如只留文档字符串:平均多 33.08 个误导测试(+1.11 个百分点),而且少 64.85 个有效测试(−1.33 个百分点)。相对「只有代码」,它只有边际收益:有效测试多 17.77 个(+0.19 个百分点),误导测试也多 8.39 个。把规格当作额外上下文加在代码旁边,并不够。对有缺陷输入,代码必须拿掉,不能只是补充。
以 Gemini 2.5 Pro 为例,只有文档字符串时误导 110 个(2.77%)、有效 198 个(4.98%);只有代码时误导 173 个(5.27%)、有效 98 个(2.98%)。
4.1 用到有缺陷代码上,以及高级分析
高级方法让模型先找出潜在缺陷并提议修复,因此可能幻觉出并不存在的「假意图」或不正确的修复,导致假阳性测试:断言的行为在有缺陷版本和修复版本里都不存在,于是两边都失败。表 10 报告这类测试的比例。基础版方法不提高这个比例。高级分析有权衡:比例从大约 16% 略升到大约 18%,但换来可观收益。相对基础版,带误导测试的焦点方法平均少 6 个(减少 12.60%),平均多发现 14 个缺陷(增加 18.88%)。
直接在仍可见的有缺陷代码上做高级分析、而不换成文档字符串,并不能同样减轻误导。高级分析必须和「用规格替换代码」合在一起。
4.2 与多轮提示
三轮精炼之后,用文档字符串做输入,平均有效测试数增加 35.69,是用有缺陷代码做输入时增加量 17.62 的两倍以上。方法级也类似,9.85 对 5.69。反过来,误导测试数在文档字符串输入下平均只增加 18.08,有缺陷代码输入下增加 31.77;方法级是 3.38 对 8.62。在多轮测试生成里,本方法仍然更有效。
4.3 文档字符串质量如何影响测试
人工检查用高级提示生成的文档字符串,覆盖应用本方法后误导测试套件减少最多和最少的两个模型:Gemini 2.5 Pro 和 Qwen3-Coder-Plus。一位作者和一位外部标注者独立标注每份文档字符串是否(1)保留原缺陷,(2)描述修正后的行为。对每个标签、每个模型分别算 Cohen 的 κ,用的是讨论前的独立标注。分歧再通过讨论解决,最终分析用共识标签。按 Landis 和 Koch 的解释,标签(1)的 κ 为 0.82 和 0.84,接近完全一致;标签(2)为 0.77 和 0.79,属于实质性一致。两个标签同时为「是」的行计数为零:若文档字符串保留了原缺陷,就不太可能同时又描述修好该缺陷所需的正确行为。
每个模型 318 份文档字符串里,只有 48 份 Gemini 生成的(15.09%)和 66 份 Qwen 生成的(20.75%)保留了原缺陷。同时,198 份 Gemini 的(62.26%)和 151 份 Qwen 的(47.48%)恢复了修好焦点方法缺陷所需的正确行为。
不含有缺陷行为的文档字符串,带来显著更少的误导测试套件;恢复了正确行为的文档字符串,贡献显著更多被发现的缺陷。Gemini 的 270 份无缺陷文档字符串只对应 43 个有误导的焦点方法中的 19 个,而 48 份保留缺陷的文档字符串对应其中 24 个。198 份恢复正确行为的文档字符串贡献 100 个被发现缺陷中的 80 个,其余 120 份只贡献 20 个。Qwen 类似:252 份无缺陷文档字符串对应 40 个有误导焦点方法中的 17 个,66 份保留缺陷的对应 23 个;151 份恢复正确行为的贡献 86 个被发现缺陷中的 55 个,其余 167 份贡献 31 个。
5 RQ3:对无缺陷代码的影响
真实应用里不知道被测代码对不对,所以方法也必须能用在无缺陷代码上。作者把方法用到基准里的无缺陷(即修复后)代码上,按先前工作常用的两条标准评测:测试正确性和测试覆盖,并与直接用无缺陷代码做提示的基线比较。
表 12 比较编译失败率(CFR,越低越好)、误报率(FAR,越低越好),以及行覆盖和分支覆盖(越高越好)。本方法把 CFR 略降 1.20 个百分点,把 FAR 略升 1.59 个百分点。总体看,对无缺陷代码,与直接用源码做提示相当。覆盖上,相对直接用源码的基线,行覆盖略增 3.61 个百分点,分支覆盖略增 2.97 个百分点。不给开发者增加额外负担,生成的测试仍可用于回归测试。
6 效度威胁与局限
外部效度。研究依赖 Defects4J。318 个焦点方法覆盖全部 17 个项目,11 个当时的前沿模型也支持一定的可推广性。Defects4J 仍可能盖不住两种真实情况。第一,在专有或高度领域专用的系统里,模型可能缺少推断预定行为所需的领域知识或上下文,从而产生幻觉的「假意图」或不正确的缺陷修复。第二,对状态很深或依赖很多的代码,方法级文档字符串可能不够。
内部与构念。为减轻模型随机性,在可能的地方把生成温度设为 0。数据污染是潜在威胁:Defects4J 的人工测试可能在训练数据里。基于文档字符串的提示可以看成一种改写,常用来减轻污染影响。而且这种提示在所有模型上都带来显著改进而不是下降,说明模型不是在简单回忆背过的测试,而是在用规格里的信息。高级提示可能引入幻觉行为,再被测试断言;表 10 把假阳性比例从约 16% 到约 18% 的上升记成了这个代价。
7 相关工作
大解码器模型使测试生成更自然、也更好维护。较早的专门方法如 CAT-LM,在对齐的代码–测试数据上训练 GPT 式模型。GPT-4、Claude、Llama 等更大的模型并未专门为单元测试训练,但在精心设计的提示下仍能产出有意义的测试。近期工作用各种提示策略提高正确性和覆盖率。
大量先前研究主要按测试正确性和覆盖率评测,对核心功能——发现缺陷——关注相对少。近期工作开始直接评估并改进大模型的缺陷检测能力,但通常用正确代码做输入,忽略被测代码常常有缺陷的真实情况。
少数近期工作开始评测从有缺陷代码生成的单元测试。Abdullin 等人报告用有缺陷代码做输入时的缺陷检测率。Li 等人从模型根据有缺陷代码推出的意图合成多个代码变体,再根据变体之间的差异生成测试。他们还认为,当有缺陷代码和修复代码只差一点点时,模型常常能推出预定行为,但证据来自一个小数据集(40 个程序)和相对简单的任务。Mathews 等人指出,有缺陷代码可能使从它生成的测试发现不了它自己的缺陷。Huang 等人表明,从有缺陷代码生成的测试在正确性、覆盖和缺陷检测上都更低,并初次尝试框定误导,但其指标把所有在有缺陷版本上通过的测试都算进去,如第 2.6 节所示,这会把大量两边都通过的有效测试算成误导。
8 结论与未来工作
本文对大模型生成测试中的误导效应做了大规模定量研究:有缺陷代码使模型把错误行为理解成预定功能。用新指标,经验上表明双重影响:增加去验证缺陷的误导测试,同时压低能发现缺陷的有效测试。从模型内部,有缺陷代码把偏好扭向断言其错误行为的误导测试。
基于规格的方法把测试生成和可能有缺陷的实现解开:用从被测代码构造的规格作为唯一的行为输入。即便简单的、由模型生成的文档字符串,也能显著减轻误导并提高缺陷检测。基于推理的代码意图分析可以进一步加强,并成为多轮交互提示更好的基础。方法对有缺陷和无缺陷代码都适用,在后者上编译失败、误报测试和覆盖与基线相当。
未来工作包括:在大规模或领域专用项目里更可靠地推断预定行为,例如把多智能体推理和静态程序分析的行为信息合在一起;探索自然语言之外的规格形式,例如 UML 或形式规格;把模型生成的规格与高质量人工规格比较,以评估减轻误导的效果,并理解这种方法的上限。
数据来自公开的 Defects4J。复现包含预处理脚本、人工检查结果,以及评测流水线和所提出方法的源码,在 https://github.com/drixs2050/EvalAndMitigate ,并在 Zenodo 归档,DOI 为 10.5281/zenodo.21428153。致谢由加拿大自然科学与工程研究理事会(资助号 RGPIN-2022-04154)和 Connaught Fund(资助号 NR-2022-23)支持。外部标注者是 Yuliang Song。
Found it useful? Pass it on
Scan with WeChat to open it on your phone and forward it.