Industry & PracticeResearch & Benchmarks
先 写 代码 再 测试 的 风险: 一项 关于 基于 大 语言 模型 的 测试 生成 工作 流 的 实证 研究
大语言模型(Large Language Models, LLMs)正越来越多地用于软件工程工作流,以自动生成源代码及其对应的测试套件。这种双重能力催生了新的开发范式,包括测试先行工作流与智能体工作流:由同一个模型负责产
In this piece
先写代码再测试的风险:一项关于基于大语言模型的测试生成工作流的实证研究(中文全译)
翻译说明:本文是 arXiv 论文 On the risk of coding before testing: An empirical study on LLM-based test generation workflow(arXiv:2607.05139)的中文全译,由智测团队翻译。原作者:Michael Konstantinou(SnT, University of Luxembourg,卢森堡)、Florian Tambon(SnT, University of Luxembourg,卢森堡)、Mike Papadakis(SnT, University of Luxembourg,卢森堡)。原文以 CC BY 4.0 许可发布。译文保留原文全部章节、数据与结论;参考文献列表从略。
arXiv:2607.05139v1 [cs.SE] 2026年7月6日
作者
Michael Konstantinou
单位:SnT, University of Luxembourg 卢森堡 邮箱:michael.konstantinou@uni.lu
Florian Tambon
单位:SnT, University of Luxembourg 卢森堡 邮箱:florian.tambon@uni.lu
Mike Papadakis
单位:SnT, University of Luxembourg 卢森堡 邮箱:michail.papadakis@uni.lu
摘要
大语言模型(Large Language Models, LLMs)正越来越多地用于软件工程工作流,以自动生成源代码及其对应的测试套件。这种双重能力催生了新的开发范式,包括测试先行工作流与智能体工作流:由同一个模型负责产出实现并对其进行验证。然而,这些做法隐含地假定所生成的测试是独立且可靠的预言机——而这正是有效软件测试的一项基本要求。本文质疑这一假定,并研究大语言模型生成的代码是否会偏置其后生成的测试。我们提出并实证考察错误传播(error propagation)现象:生成代码中存在的故障会被系统地复制到相关测试制品之中。由此会出现不正确的实现与测试彼此一致的情形,从而掩盖缺陷,而不是揭示缺陷。我们在一系列编程任务与智能体工作流上评估这一效应,分析生成代码与测试断言之间的一致性,并特别关注对齐失败(aligned failures)的场景。本研究考察:(i)错误的代码制品是否会偏置测试生成;(ii)这种偏置在不同提示策略(包括思维链推理)下是否仍然存在;(iii)在把中间输出复用为上下文的多步工作流中,错误如何传播。结果表明,错误传播既普遍又有实质影响:在故障代码之后再生成测试,其故障检测有效性显著低于独立生成测试(14% 对 25%)。这些发现揭示了当前工作流的一项根本局限:生成制品之间缺乏独立性,会削弱自动化测试的可靠性。此外,我们的结果还暴露了依赖耦合生成流水线的实证研究中一项此前未被充分探讨的效度威胁。
索引词: 基于大语言模型的测试生成,错误传播
I 引言
大语言模型正日益被集成到软件工程工作流中。它们不仅被用来生成生产代码,也被用来合成配套的测试套件。这种双重能力助长了对高度自动化开发流水线的乐观设想:实现与验证都被委托给同一个生成系统。尤其是,近期的工具链推动测试先行或协同演化工作流,由大语言模型先生成候选测试,再生成满足这些测试的代码,从而有望在减少人力的同时加快开发。
然而,这一范式隐含地假定:大语言模型生成的测试能为正确性评估提供独立且可靠的预言机。在传统软件测试中,有效性关键取决于被测系统与测试预言机之间的独立性 [1, 2]。当两件制品都由同一个底层模型产生时,这一假定可能不再成立。
本文通过考察“大语言模型生成故障代码是否会偏置测试生成”来检验这一基本假定。当模型被要求为同一问题同时产出两件制品时,它很可能依赖相似的内部表示、假定与推理轨迹。这种共享的生成过程提高了如下可能性:错误并非相互独立,而是被系统地复制,从而使测试编码并认可生成代码所表现出的同一种不正确行为。
此外,大语言模型的自回归特性会加剧这一问题。这些模型逐词元生成输出,每一步都以前面已生成的内容为条件 [3, 4]。因此,当模型产出含有错误的代码时,这份故障输出就会成为塑造后续生成的上下文的一部分。于是,后续活动——例如测试生成——可能被更早的错误所隐性偏置,从而增加把错误假定传播到不同制品上的风险。
这意味着,代码合成阶段引入的错误——例如对规格说明、边界条件或边缘情形的错误解释——并非独立于后续测试活动。相反,它们常常在测试生成过程中被复制,包括在构造测试预言机(例如断言)时。这一行为在智能体工作流中尤为关键,特别是在自主智能体以极少人工干预迭代求解任务的“氛围编程”(vibecoding)场景中。进一步地,它也给那些没有把代码生成与测试生成隔离开来的实证研究带来隐忧:这种耦合可能系统性地偏置评估结果。
我们将这一现象称为错误传播:实现故障被生成测试中的相应故障所镜像。在这类情形中,测试所验证的是不正确行为,而不是将其暴露出来,从而制造一种虚假的正确感。重要的是,这并不仅仅是提示设计不佳或训练数据有限的后果,而是自回归生成的结构性效应:相似的概率偏置与推理模式会在相关输出之间被反复使用。
近期研究已经表明,把错误制品(例如故障代码)纳入提示会降低大语言模型的表现。在测试预言机生成的语境中,已有研究表明:提示中包含不正确或具有误导性的代码,会负面影响所生成断言的正确性,并降低其作为验证机制的有效性 [5, 6, 7]。在这些发现之上,我们认为错误制品的影响会超出单个任务,延伸到多步工作流;而多步工作流更贴近现代智能体系统与“氛围编程”的当前实践。在这类设置中,中间输出——其中可能含有错误——被显式地复用为后续步骤上下文的一部分,形成塑造未来生成的迭代反馈回路。
此外,当代大多数智能体工作流依赖提示分解或规划策略,把复杂任务拆成逐步处理的子任务序列。尽管与单次提示相比,这类结构化方法通常能提高表现,但它们在步骤之间引入了很强的相互依赖,因为每个子任务都以前序步骤产出的制品为条件。于是,推理步骤之间相互独立的假定不再成立。较早阶段引入的错误可能偏置或约束后续生成,从而在整个工作流中产生级联效应。
鉴于工作流设计是影响基于大语言模型的系统表现的关键因素,我们针对多样化的编程任务,对智能体式的代码与测试生成工作流开展实证研究。具体而言,我们分析生成的实现与其对应测试断言之间的一致性,并特别强调两件制品都不正确、却彼此一致的情形。这类情形尤其成问题,因为尽管底层存在故障,它们仍可能错误地表明正确性。
为研究这一现象,我们首先考察:纳入错误的代码制品,是否会偏置随后生成的测试及其关联预言机的正确性。然后,我们评估这种偏置在不同提示策略下是否仍然存在,包括思维链提示等结构化推理方法——这些方法会显式引导模型经过中间步骤。
在确认该效应存在之后,我们进一步评估它在多步智能体工作流中传播的程度。具体而言,我们研究较早阶段引入的错误——例如不正确的代码生成——是否会延续到较后阶段(例如测试生成),从而诱发系统性偏置。这使我们能够刻画:在现实的、逐步推进的、由大语言模型驱动的开发流水线中,易错的中间制品如何影响下游组件。
我们的结果表明,此类对齐失败频繁发生,显著降低了测试作为验证机制的有效性。即使应用了提示技术,这些失败仍然出现;从某种意义上说,思维链提示似乎没有效果。特别是,在代码生成之前生成测试,故障检测率达到 25%,显著高于在错误代码之后生成测试时所观察到的约 14% 的故障检测率。
这些发现对人工智能辅助的软件工程工具设计具有重要启示。它们表明:用同一个模型同时生成代码和测试,并不能保证有意义的验证,反而可能引入一类未被检出的新故障。这挑战了关于大语言模型驱动测试之收益的常见假定,并凸显出在验证过程中引入独立性、多样性或外部依据的必要性。
也许更为重要的是,我们的结果揭示了基于大语言模型的评估协议中一项根本的效度威胁。具体而言,工作流中较早步骤对后续步骤的影响会人为扭曲性能测量,从而同时影响所提出的方法与基线方法。尽管已有工作指出了错误提示的负面影响,但此前尚无研究系统考察错误在工作流步骤之间的传播影响,而这正是现代智能体系统的核心所在。
II 背景
II-A 智能体系统
智能体系统可以抽象为:被赋予与周围环境交互并采取行动之能力的大语言模型。传统大语言模型是在固定上下文(“提示”)上做预测;智能体则允许大语言模型借助记忆(以保留上下文信息)、规划能力(推理)以及对多种工具的访问,与用户及环境交互。就其当前形态而言,智能体系统基于 ReActIng 框架,即推理(Reasoning)、行动(Acting)与交互(Interacting)[8]。本文主要关注对推理部分的影响,因为我们关心的是智能体为求解问题所采取的工作流步骤。把推理应用于面向测试生成的智能体有若干不同方式 [9],因此我们将聚焦于已被用于测试生成的技术。尽管高级智能体系统可能会组合其中多种技术,本研究将单独使用这些技术,以评估其对性能的各自贡献。行动与交互部分将通过一个简单过程来模拟:允许智能体在代码上执行所生成的测试,接收反馈,并依照既有的大语言模型提示方法修改其答案。
II-B 基于大语言模型的测试生成
智能体流水线包含一个交互回路,大语言模型在其中作为软件环境内的自主智能体行事 [10]。在这些架构中,通过零样本提示、执行,并基于执行反馈或编译错误迭代修复测试代码,代表了智能体的“行动”与“交互”阶段。然而,这些方法很快会遇到瓶颈,因为它们缺少在采取行动之前理解复杂语义所需的恰当“推理”阶段。为弥合这一差距,当代框架把显式的推理抽象注入智能体上下文。例如,ChatAssert [11] 一类技术利用自动代码摘要,把焦点方法的功能提炼为自然语言,在预言机生成期间直接引导大语言模型的上下文理解。思维链一类方法则迫使智能体在生成语法有效的测试断言之前,显式梳理执行路径或代码结构 [12]。通过从不受约束的试错式生成,转向结构化的、无需执行的语义分析,这些推理机制减轻幻觉,并抵消大语言模型代码生成在逻辑上的脆弱性。
III 研究问题
基于大语言模型的测试生成近期进展引入了多种旨在提高生成测试套件质量的策略。尽管这些方法各不相同,它们几乎普遍依赖向语言模型暴露被测实现,或者显式地提供源代码,或者以隐式方式暴露。尽管这一设计选择已成为常见实践 [13],其对故障检测有效性的影响在很大程度上仍未被探索,在现代由大语言模型辅助的编程场景(例如智能体软件工程,如氛围编程)中尤其如此。
因此,我们首先考察:向模型暴露被测实现,是否真的有益于基于大语言模型的测试生成;以及已有工作所提出的优化策略,相对于直接依据任务规格生成测试,是否提供了额外价值。于是我们提出:
RQ1(实现的影响): 无论是显式还是隐式地暴露于实现代码,在多大程度上影响大语言模型所生成单元测试检测故障的能力?
我们通过比较测试生成提示中存在代码与不存在代码时检出故障数量的差异来研究这一问题。从某种意义上说,我们检验的是:当从同一提示(任务描述)生成代码时,若把生成的代码纳入或不纳入测试生成,测试生成实际上能否检出大语言模型所生成的那些故障。
RQ1 的目的是检验是否存在一种效应,即故障实现会偏置测试生成。鉴于我们发现证据表明:在提示中纳入故障实现会偏置测试生成并对其产生负面影响,我们进而考察同一现象在使用不同提示策略时是否仍然存在,例如经由摘要的测试(Test via Summarization)、思维链(Chain-of-Thought, CoT)以及验证链(Chain-of-Verification, CoVe)。于是我们提出:
RQ2(提示策略): 暴露于实现代码,在经由摘要的测试、CoT 与 CoVe 等不同提示策略下,在多大程度上影响大语言模型所生成单元测试检测故障的能力?
我们通过比较不同提示策略下存在代码与不存在代码时检出故障数量的差异来研究这一问题,分析方式与 RQ1 类似。
前两个研究问题量化了在所分析的提示中纳入错误代码的有害影响,但它们并未表明:工作流、尤其是过去的任务,会在后续活动中造成隐性偏置。因此我们提出:
RQ3(工作流): 典型的智能体工作流,与缺少实现存在的工作流相比如何?
我们通过比较在任何代码生成之前生成测试与在代码生成之后生成测试时检出故障数量的差异来研究这一问题。从某种意义上说,这是在比较代码生成尝试所施加的隐性偏置。
IV 实验设置
IV-A 方法
图 1: 方法。生成并筛选故障实现以构建评估数据集。所得实现随后用于评估所研究的基于大语言模型的测试生成技术的有效性。
给定一项编程任务,开发者可以利用大语言模型或基于大语言模型的编码助手,从自然语言规格生成一份实现。随后,开发者或自动化工具可以提示同一个模型生成单元测试,目的是验证该实现并发现潜在故障。
学术界与工业界都已提出大量使用大语言模型生成测试的方法。尽管这些方法各不相同,它们通常或显式或隐式地依赖对被测实现的访问。因此,生成的代码常常被用作指导测试生成的首要信息来源。
本文考察:要有效地生成测试,访问实现是否必要。具体而言,我们把现有的、感知代码的测试生成工作流,与一个仅依赖原始任务描述、完全不访问生成实现的简单基线进行比较。由此,我们评估自然语言规格本身在多大程度上包含足以指导揭示故障的测试生成的信息。
为开展这项研究,我们执行如下步骤。首先,对每项编程任务,使用大语言模型生成一个或多个候选实现。其次,识别并仅保留故障实现,从而构建一个不正确解的基准。最后,对每个故障实现应用一系列测试生成工作流,并评估其检测故障的有效性。这一实验设计使得能够在感知实现的测试生成与由规格驱动的测试生成之间进行系统比较,从而揭示代码与任务描述作为测试信息来源的相对价值。
数据收集: 为构建故障实现数据集,我们采用三个公认的编程基准。每个基准都提供任务描述、参考实现,以及用于验证生成解的测试套件。对每项任务,我们提示每个模型仅依据任务描述生成实现。为获得多样化的候选实现并减轻采样偏置,我们以温度 0.8 为每项任务生成十个解,以鼓励模型输出的变异。
每个生成的实现都对照基准的参考测试套件执行。由于本研究关注生成测试在检测行为故障方面的有效性,我们仅保留那些对至少一个测试用例产生不正确输出的实现。因运行时错误、异常或其他执行失败而失败的实现被排除。
故障排序与选择: 上一阶段为每项编程任务产生一组候选故障实现。然而,同一任务可能生成多个故障实现,其中一些所含故障可能平凡易检。
为获得有代表性且具有挑战性的评估数据集,我们对生成的实现应用如下筛选准则。
- 故障排序。 每个实现根据暴露其故障的参考测试用例比例被赋予一个难度分数。具体而言,我们用失败测试的数量作为故障可检测性的代理:在基准测试套件中失败比例很大的实现被视为更容易检测;仅有少量测试用例失败的实现被视为更难暴露,因为它们需要更有针对性的测试输入。
- 故障过滤。 我们的目标是在其故障不会被基准参考测试套件平凡暴露的实现上评估测试生成技术。因此,我们排除参考测试用例失败比例超过 50% 的实现。该阈值作为一种务实的过滤准则,用以去除其故障已被很大一部分现有测试检出的实现,使评估能够聚焦于更具挑战性的故障场景。
- 实现选择。 对每项编程任务,若存在故障实现,我们只保留一个。当存在多个候选时,我们选择估计难度最高的实现(即失败的参考测试用例最少的那个),从而优先考虑不那么容易被现有测试暴露的故障。
基于大语言模型的测试生成: 为评估暴露实现对测试生成的影响,我们需要一种测试生成工作流,它能尽量减少混杂因素,并使性能差异可以仅归因于所考察的测试策略。因此我们采用 LLM-Plain [13],这是一种轻量的测试生成方法,仅依赖底层大语言模型的推理能力。
先前大多数技术针对的是所谓回归测试的创建 [5],因而假定被测代码的行为是正确的,也就是说,它们在构造上就不能揭示故障 [7]。LLM-Plain 包含一个迭代精炼回路,类似于现代基于大语言模型的测试生成工具与智能体编码工作流所采用的回路,模型在其中迭代地纠正无效输出。在本研究中,我们修改这一精炼回路,使其只修复编译错误。这保证生成的测试套件可执行,而断言(预言机)由大语言模型选出,其意图是揭示候选故障。已有工作表明,LLM-Plain 能取得与最先进的基于大语言模型的测试生成工具相当的性能 [13],因而适合作为我们评估的基线。
IV-B 基准
为评估本研究提出的测试生成技术与工作流,我们采用三个被广泛使用的代码生成基准。每个基准由一组编程任务组成,包括自然语言问题规格、参考实现,以及用于验证候选解的可执行测试套件。由于这些基准只包含正确的参考实现,我们按照第 IV-A 节所述方法,用它们构建故障实现数据集。配套的参考测试套件随后既用于识别故障实现,也用于评估每种技术所生成测试套件的故障检测有效性。具体而言,我们使用如下基准:
- HumanEval+: [14] [15] HumanEval+ 是被广泛使用的 HumanEval 基准的扩展,为每项编程任务增补了显著更全面的测试套件。它包含 164 个以自然语言描述的 Python 编程问题,并配有参考实现与大量测试。
- MBPP: [16] Mostly Basic Python Problems(MBPP)是一个包含 974 个众包 Python 编程任务的基准,覆盖范围广泛的入门级编程概念。
- BigCodeBench: [17] BigCodeBench 是为在更现实、更具挑战性的编程任务上评估大语言模型而设计的基准。与 HumanEval+ 和 MBPP 相比,它所含问题复杂得多,常常需要多个推理步骤并使用外部库,从而更接近真实世界的软件开发。该基准由 1,140 个编程任务组成,涉及 139 个 Python 库。
IV-C 模型
我们采用来自不同提供方的 5 个最先进语言模型:GPT-5-mini、GPT-4.1-mini、DeepSeek-V4-Flash、Claude Haiku 4.5 以及 Llama 3.3 Instruct(70B)。所选模型代表多样的能力范围,既包括天生启用推理的模型与非推理模型,也包括开放权重模型与商业可用模型。这种多样性使我们能够在不同模型家族与部署设置上评估所观察效应的可推广性。表 I 列出我们所使用的模型,并标明每个模型是否为开放权重,以及其推理能力是否受支持并在本研究中被使用。
表 I: 所使用的语言模型及其开放权重可用性与所使用的推理能力
| 模型 | 开放权重 | 推理 |
|---|---|---|
| GPT-5-mini | ✗ | ✓ |
| GPT-4.1-mini | ✗ | ✗ |
| DeepSeek-V4-Flash | ✓ | ✗ |
| Claude Haiku 4.5 | ✗ | ✓ |
| Llama 3.3 Instruct(70B) | ✓ | ✗ |
IV-D 测试生成策略
现代基于大语言模型的测试生成工具通常组合多种提示策略、迭代精炼回路与辅助分析,以提高生成测试套件的质量。我们的目标不是评估这些工具本身,而是评估它们在不同工作流中使用时所产生的影响。所选策略反映了基于大语言模型的测试生成的当前实践状况,因为每一种都曾在先前工作中被提出,或已被现有测试生成工具采用。
基线: 由于我们旨在研究推理工作流对智能体代码—测试生成性能的影响,我们考虑一个不附加任何推理能力的简单智能体基线。我们使用 LLM-Plain [13],即以简单的迭代错误精炼回路来保证测试套件可执行。这提供了一定的智能体能力,但不包含任何附加的推理能力,从而使我们能够独立地分离并评估每种策略的贡献。
经由摘要的测试: 测试摘要是这样一种策略:在生成对应测试套件之前,先提示大语言模型总结被测代码。其直觉是,自然语言摘要会引导模型把握预期行为。该策略由 ChatAssert [10] 提出,旨在生成测试断言。
思维链(CoT)[18]: 在生成最终测试套件之前,鼓励大语言模型显式推理实现的预期行为,并识别应当测试的相关场景。所得推理随后用于指导单元测试的后续生成。CoT 已被成功地纳入代码生成工作流 [19]。
验证链(CoVe)[20]: 与鼓励在生成回答之前进行推理的思维链不同,验证链在产生初始回答之后引入一个自我验证阶段。大语言模型首先生成候选测试套件,随后被提示一系列验证问题,以鼓励它识别并纠正潜在错误。CoVe 及类似设计已在若干研究中被用于改进代码与测试生成 [21, 22, 23]。
智能体工作流: 与前述技术不同,该工作流模拟从最初的代码生成请求开始的一次交互会话。模型首先收到代码生成请求并产出(故障)实现。用户随后要求同一个模型生成单元测试。为实现这一点,我们在单次会话中保留从代码生成到测试生成的全部对话历史。为确保所有工作流都在相同的故障实现上被评估,我们控制模型最初的代码生成回答,使其精确匹配较早阶段收集到的故障实现。
IV-E 指标
我们使用两个互补指标评估生成测试套件的有效性。故障触发衡量生成的测试是否在实现中行使了故障行为;故障检测则额外要求所观察到的失败可归因于正确的测试预言机。
故障触发: 若某个生成的测试触发了与参考实现不同的行为,则认为故障已被触发,与该测试所使用的具体断言语句无关。严格而言,若通过测试断言所检查的程序输出,在故障实现与参考实现之间检测到行为差异,则认为故障已被触发,无论该故障是否被检测出来。例如,某条测试断言可能在参考实现与故障实现上都会失败,但只要我们检测到两个程序给出了不同的输出,该测试仍然触发了故障。这意味着故障触发是故障检测的更弱前提条件;故障触发情形与已检测情形之间的任何差异,都表明断言被错误地表达。
故障检测: 若某测试在故障实现上执行时失败,同时在对应的参考实现(假定为正确)上通过,则认为故障已被检测。换言之,若故障被触发并且被测试正确地检出,则该故障被检测。
故障可检测性: 我们引入故障可检测性指标,以估计一个故障被测试套件触发的难易程度。直觉上,被许多测试用例所行使的故障,比需要高度特定的输入与输出断言的故障更容易检测。据此,我们用如下分数估计故障可检测性:
$$D(i)=1-\frac{|F_i|}{|T|}$$
其中 $T$ 表示测试套件,$F_i\subseteq T$ 是对实现 $i$ 失败的测试用例子集。$D(i)$ 的值越高,对应那些其故障被更少参考测试用例所暴露的实现,因而被认为越不容易被检测。我们仅在数据集构建期间使用该指标,对故障实现排序,并排除其故障被平凡暴露的实现,如第 IV-A 节所述。
统计显著性: 我们采用 Mann-Whitney U 检验 [24] 来判断所观察到的结果是否具有统计显著性。依照标准做法,当所得 $p$ 值低于 0.05 时,我们认为结果具有统计显著性。
V 研究方案
为回答 RQ1,我们进行三项互补实验,评估代码暴露对基于大语言模型的测试生成的影响。在所有实验中,我们采用第 IV-A 节所述的 LLM-Plain 工作流,以确保在不同配置中被控制的唯一方面就是所评估的策略。
我们首先评估在测试生成期间暴露被测实现的直接影响。与先前工作 [5] 不同——该工作使用与大语言模型的单次交互来比较提示策略——我们在一种反映现代测试生成方法设计的、现实的基于大语言模型的测试生成工作流中进行比较。我们使用三种输入配置生成测试套件:(1)仅任务描述;(2)任务描述与被测实现;(3)仅被测实现。需要指出的是,每种配置与每项任务都在一次全新试验上进行,以避免先前运行带来的潜在偏置。
为回答 RQ2,我们考察近期基于大语言模型的测试生成与代码生成工作流所常用的提示工程技术,是否能减轻实现暴露的影响。我们把仅任务描述的基线与三种有代表性的策略进行比较:基于摘要的测试生成 [10]、思维链提示 [18] 以及验证链 [20]。
为回答 RQ3,我们模拟一种典型的氛围编程(智能体)工作流:开发者先提示大语言模型根据任务描述生成实现,随后为所生成的代码请求单元测试套件。为忠实地复现这一交互,我们在整个工作流中保留对话历史。具体而言,模型首先收到任务描述并生成实现。由于我们关心的是模型生成故障代码时会发生什么,我们只考虑这些情形,即丢弃模型生成正确代码的情形,只保留故障情形。然后我们提示模型生成单元测试。
这一设置反映了当代基于大语言模型的编码助手的行为:模型保留对先前交互的访问。
我们把该工作流与 RQ1 中引入的任务描述工作流进行比较。与智能体工作流相反,测试生成是在与大语言模型的一次全新交互中进行的,其中只包含任务描述,没有来自先前代码生成过程的对话上下文。因此,生成的实现既没有被显式暴露给模型,也没有被隐式暴露。在本文其余部分,我们把前者称为智能体工作流(Agentic Workflow),把后者称为测试驱动工作流(Test-Driven Workflow),因为测试生成是独立于代码生成而进行的。
VI 结果
VI-A RQ1:实现的影响
图 2: RQ1:所有模型与基准上的故障检测。仅从任务描述生成测试用例会带来更高的故障检测率。
图 2 给出了当大语言模型只获得任务描述、只获得代码,或同时获得两种信息时的故障检测有效性。我们观察到,在所有情形中,直接从任务描述生成的测试套件都检出了更多故障。具体而言,在任务描述之外再提供被测实现,使故障检测分别下降了 9.1%、15.2%、18.2%、12.9% 与 10.7%,对应模型依次为 Claude Haiku 4.5、DeepSeek V4、GPT-4.1 mini、GPT-5 mini 与 Llama 3.3(70B)。
一个有趣的观察是:一旦被测实现被暴露给模型,伴随的任务描述只带来边际改进。平均而言,仅从实现生成测试,与从任务描述和实现两者共同生成测试之间的差异只有 1.9%;而仅提供任务描述,相对于组合配置有 13.2% 的改进。这表明,一旦实现被引入模型,模型主要依赖实现,而不是任务描述。
表 II 证实了上述观察。该表汇总了成对比较的统计显著性。在所有被评估的模型上,仅任务描述配置与两种暴露被测实现的配置之间的差异都具有统计显著性。
相反,在“从任务描述与实现两者生成测试”和“仅从实现生成测试”之间,没有观察到统计上显著的差异。
表 II: RQ1:三种配置成对比较的统计显著性:仅提示(P)、提示与代码(P+C)、仅代码(C)
| 模型 | P 对 P+C | P+C 对 C | P 对 C |
|---|---|---|---|
| Claude Haiku 4.5 | ✓(p=0.009) | ✗(p=0.621) | ✓(p=0.002) |
| DeepSeek V4 | ✓(p<0.001) | ✗(p=0.793) | ✓(p<0.001) |
| GPT-4.1-mini | ✓(p<0.001) | ✗(p=0.777) | ✓(p<0.001) |
| GPT-5-mini | ✓(p<0.001) | ✗(p=0.212) | ✓(p<0.001) |
| Llama 3.3 Instruct(70B) | ✓(p=0.001) | ✗(p=0.160) | ✓(p<0.001) |
发现 1: 暴露被测实现会一致地降低大语言模型所生成测试套件的故障检测有效性。与仅使用任务描述相比,同时提供任务描述与实现使故障检测平均下降 13.2%;而仅提供实现则导致平均下降 15.1%。
VI-B RQ2:提示策略
图 3 展示了每种所用提示工程技术取得的故障检测。我们观察到,仅从任务描述生成测试套件,仍然比任何包含被测代码的方法更有效。更精确地说,在所有被评估的模型上,仅提示都比基于摘要的工作流取得更高的故障检测,改进幅度分别为 11.4%、17.5%、20.7%、15.3% 与 12.8%,对应 Claude Haiku 4.5、DeepSeek V4、GPT-4.1 mini、GPT-5 mini 与 Llama 3.3(70B)。思维链呈现类似趋势:仅提示使故障检测分别提高 9.8%、14.1%、25.8%、12.9% 与 9.5%。同样,相对于验证链,仅提示在相同模型上分别取得 7.6%、16.0%、16.7%、15.3% 与 11.3% 的改进。
发现 2: 直接从任务描述生成测试套件,比提示工程技术更有效;故障检测在摘要策略下下降 15.5%,在思维链与验证链下均下降 13.4%。
图 3: RQ2:使用提示工程技术时的故障检测。
表 III: RQ2:仅提示与三种提示技术之间的统计显著性
| 模型 | 摘要 对 仅提示 | CoT 对 仅提示 | CoVe 对 仅提示 |
|---|---|---|---|
| Claude Haiku 4.5 | ✓(p=0.0008) | ✓(p=0.0042) | ✓(p=0.0311) |
| DeepSeek V4 | ✓(p<0.0001) | ✓(p=0.0001) | ✓(p<0.0001) |
| GPT-4.1-mini | ✓(p<0.0001) | ✓(p<0.0001) | ✓(p=0.0001) |
| GPT-5-mini | ✓(p<0.0001) | ✓(p<0.0001) | ✓(p<0.0001) |
| Llama 3.3 Instruct(70B) | ✓(p=0.0001) | ✓(p=0.0042) | ✓(p=0.0005) |
VI-C RQ3:工作流
图 4 给出了智能体工作流与测试驱动工作流在所有被评估基准上的故障检测有效性。与 RQ1 的发现一致,所有被评估模型在测试驱动工作流下的故障检测率都高于智能体工作流。具体而言,相对于智能体工作流,测试驱动工作流使故障检测提高了:Claude Haiku 4.5 为 10.6%,DeepSeek V4 为 13.8%,GPT-4.1-mini 为 17.7%,GPT-5-mini 为 13.6%,Llama 3.3(70B)为 7.9%。如表 IV 所报告,所有差异均具有统计显著性。
所观察的趋势在所有被评估模型上一致,并且似乎并不取决于是否使用推理能力。例如,GPT-5-mini 与 DeepSeek V4 都表现出约 14% 的改进,但只有前者使用了我们所采用的推理。
发现 3: 测试驱动工作流一致地生成故障检测有效性更高的测试套件,平均比智能体工作流多检出 11.7% 的故障。
表 IV: RQ3:智能体工作流与测试驱动工作流比较的统计显著性
| 模型 | 智能体 对 测试驱动 |
|---|---|
| Claude Haiku 4.5 | ✓(p=0.0019) |
| DeepSeek V4 | ✓(p=0.0001) |
| GPT-4.1-mini | ✓(p<0.0001) |
| GPT-5-mini | ✓(p<0.0001) |
| Llama 3.3 Instruct(70B) | ✓(p=0.0177) |
图 4: 不同工作流下的故障检测
VII 对欠指定提示、覆盖率、故障触发与测试数量的控制
VII-A 定性分析
我们的实证分析从故障检测的角度评估测试驱动工作流的有效性。然而,这一分析并不能解释为什么某些策略优于其他策略。为更好地理解所观察到的差异,我们使用刻画生成测试套件的附加指标进行诊断分析。
具体而言,我们考察三个互补方面。第一,我们测量生成的测试用例数量,因为已有工作指出,某些提示策略会使大语言模型产出更全面的测试套件 [13],这可能影响故障检测有效性。第二,我们测量语句覆盖率,以判断代码覆盖率的差异是否能解释所观察到的性能差距,如先前工作所示 [25]。
最后,我们评估故障触发,以判断生成的测试套件是否主要在验证当前实现——这一现象此前已在大语言模型生成的测试预言机中被观察到 [7]。
表 V: 每个模型与每种技术生成的测试用例总数。每行最高值以粗体标出,次高值加下划线。
| 模型 | 摘要 | 仅提示 | P+C | 仅代码 | CoT | CoVe | 智能体 |
|---|---|---|---|---|---|---|---|
| Claude Haiku 4.5 | 4133 | 4374 | 4516 | 4488 | <u>5860</u> | 7789 | 4727 |
| DeepSeek V4 Flash | 2111 | 2361 | 2489 | 2449 | <u>2912</u> | 3262 | 2480 |
| GPT-4.1 Mini | 1221 | 1406 | 1398 | 1395 | <u>1727</u> | 1953 | 1255 |
| GPT-5 Mini | 1971 | 1521 | 1951 | 1875 | <u>2126</u> | 2701 | 2086 |
| Llama 3.3 70B Instruct | 2297 | 2295 | 2262 | 2244 | <u>2714</u> | 3487 | 2351 |
表 V 报告了每个模型生成的测试总数。总体而言,直接从任务描述生成测试(仅提示)并不会产生最大的测试套件。相反,提示技术 CoVe 与 CoT 在所有模型上都一致地生成更多测试。尽管如此,尽管它们产出了更大的测试套件,这两种技术在故障检测有效性上都不优于仅提示方法。这一点在 Claude Haiku 4.5 上尤为明显:CoVe 生成的测试数量几乎是两倍,但仅提示仍然取得更好的故障检测。这些发现表明,直接从任务描述生成测试的有效性,不能用测试用例的数量来解释。
表 VI 报告了每种模型—配置组合下,生成测试套件所达到的平均语句(行)覆盖率。直觉上,覆盖率更高的测试套件行使更多执行路径,这可能导致更好的故障检测。尽管关于对故障检测最有效的测试充分性准则仍有持续研究 [25],考察语句覆盖率与故障检测之间的关系,仍可能揭示覆盖率是否解释了所观察到的差异。总体而言,我们没有观察到语句覆盖率与故障检测之间存在一致关系。虽然直接从任务描述生成测试在 DeepSeek V4 上取得了最高的语句覆盖率,这一模式在其余模型上并不成立。同样,语句覆盖率相近甚至更高的配置,并不必然取得更高的故障检测率。因此,所观察到的差异不太可能归因于被覆盖代码行的比例。
图 5 展示了我们结果中报告的故障检测率,以及与之对应的故障触发率。我们观察到,故障触发与故障检测并不一致相关。例如,直接从任务描述生成测试套件在各模型上取得了最高的故障检测率,但它常常表现出最低的故障触发率。然而,智能体工作流的故障检测高于仅从实现生成测试,而且除 GPT-5 mini 之外,其故障触发率在所有模型上也更高。
发现 4: 基于定性分析,我们不能把所观察到的故障检测差异归因于测试数量、语句覆盖率或故障触发。这些结果表明,测试套件的有效性很可能受所生成断言的质量影响。虽然本研究没有直接评估预言机的正确性,这些发现提示:提高生成测试预言机的质量,可能是未来工作的一个有前景的方向。
图 5: 故障检测与故障触发。底部数值表示故障检测,堆叠条报告对应的故障触发率。
表 VI: 所有模型与测试生成工作流上的平均行覆盖率。每个模型的最高值以粗体标出,次高值加下划线。
| 模型 | 摘要 | 仅提示 | P+C | 仅代码 | CoT | CoVe | 智能体 |
|---|---|---|---|---|---|---|---|
| Claude Haiku 4.5 | 97.31% | 97.26% | 97.51% | 94.69% | 97.90% | <u>97.81%</u> | 97.37% |
| DeepSeek V4 | 98.38% | 99.19% | 98.94% | 95.56% | <u>99.17%</u> | 98.87% | 98.78% |
| GPT-4.1-mini | 97.85% | <u>98.12%</u> | 98.00% | 95.13% | 98.20% | 97.91% | 96.60% |
| GPT-5-mini | 96.70% | 96.63% | 96.72% | 82.84% | <u>96.97%</u> | 97.71% | 95.22% |
| Llama 3.3 Instruct(70B) | 95.91% | 95.73% | 95.26% | 92.76% | 96.15% | 94.96% | <u>96.04%</u> |
VII-B 使用欠指定提示的故障检测
我们的结果表明,仅从任务规格生成测试,一致地优于暴露被测实现的工作流。这一观察引出一个自然的问题:当任务规格本身欠指定时,大语言模型所生成测试套件的故障检测有效性如何变化?
已有研究探讨了欠指定提示对生成代码正确性的影响 [26]。作者引入了三种减少任务规格中所提供语义信息的提示变体。
在本研究中,我们采用相同的提示变体,以考察提示欠指定是否同样影响大语言模型所生成测试套件的故障检测有效性。
我们在 MBPP 基准上进行这一分析。Akli 等人 [26] 为该基准的每项任务描述提供了三种欠指定变体。使用这些变异后的提示,我们对所有被评估模型重复测试生成实验。与主要评估一样,大语言模型只接收任务描述作为输入。不过在本实验中,原始提示被替换为对应的欠指定变体。
图 6: 使用弱提示时 MBPP 任务上的故障检测
图 6 给出了在 MBPP 上,当测试套件分别从原始任务描述、从被测实现,以及从逐步欠指定的任务描述生成时的故障检测有效性。与 RQ1 的发现一致,仅从任务描述生成的测试套件,在所有被评估模型上都一致地优于从实现生成的测试套件。即使任务描述被有意削弱,这一趋势仍然存在,表明欠指定提示中所保留的语义信息,对测试生成仍然比直接暴露被测实现更有益。具体而言,欠指定、词汇模糊以及修改语法格式的提示,相对于提示与代码工作流,平均故障检测分别高出 14.0%、11.6% 与 10.6%。
另一项观察是:对某些模型而言,从欠指定提示生成的测试套件比从原始任务描述生成的测试套件检出了更多故障。尽管这些差异还不够一致,不足以得出欠指定提示总体上更优的结论,但它们仍然与 Akli 等人 [26] 的发现相符。作者表明,任务描述可能在无意中使模型困惑,而不是引导模型;欠指定提示则允许模型推理并推断预期行为。
发现 5: 无论任务描述的质量如何,直接从任务描述生成测试套件,都比从实现生成测试带来更高的故障检测有效性。
VIII 相关工作
总体而言,现有文献主要用覆盖率、编译通过率或故障检测能力等指标来评估大语言模型所生成测试的质量。虽然这些研究确立了使用大语言模型进行测试生成的可行性,但它们通常假定生成的实现是固定且正确的,并且不考察活动顺序——先生成代码再生成测试,相对于先生成测试再生成代码——如何影响测试揭示实现缺陷的能力。我们的工作通过实证研究“先代码后测试”工作流来填补这一空白。我们并不只关注测试质量,而是考察:在创建代码之后再生成测试,是否会提高测试继承实现中相同假定、误解或缺陷的可能性。因此,本研究为开发工作流中由大语言模型辅助的测试所带来的风险提供了新的认识。
VIII-A 测试生成的实证研究
若干研究考察了大语言模型生成测试的能力 [13, 27, 28]。Konstantinou 等人 [13] 考察了四种有代表性的、带执行反馈的(基于大语言模型的)测试生成方法(HITS [29]、SymPrompt [30]、TestSpark [31] 与 Coverup [32])相对于简单的 LLM-plain 基线的表现。他们表明,在使用较新的大语言模型时,LLM-plain 优于现有方法。Yuan 等人 [28] 研究了用 ChatGPT 进行单元测试生成,发现许多测试会导致编译错误,因此提出集成编译反馈来减少这些错误。Abdullin 等人 [33] 把符号执行或基于搜索的软件测试(SBST)等传统测试生成方法与基于大语言模型的方法进行比较。他们观察到,基于大语言模型的方法在变异分数上可以优于更传统的方法。
上述研究的目标都是生成断言所观察到的程序行为的回归测试,因此在构造上不能检出被测目标实现中的故障 [7, 27]。要检测故障,测试需要配备断言预期程序行为的预言机。为此,TOGA [34] 与 TOGLL [35] 使用 Evosuite 生成测试前缀,并利用大语言模型生成测试预言机。他们发现大语言模型会生成许多错误断言。Konstantinou 等人 [7] 表明,在大语言模型提示中纳入故障代码,会对所生成断言的正确性产生负面偏置,使其难以检测故障。更进一步,Huang 等人 [27] 表明,把故障代码与任务描述(或正确代码)一起使用,会提高测试/断言的故障检测能力。
与上述研究类似,我们使用大语言模型从任务描述生成测试与预言机,并且不在候选提示中纳入任何故障代码,以避免潜在偏置。不同之处在于:我们并不检验在提示中纳入故障实现的影响,而是考察在智能体工作流中,于较早步骤进行代码生成所带来的间接影响。
VIII-B 用于代码生成的大语言模型
已有大量工作研究使用大语言模型进行程序合成。人们提出了许多策略与提示工程技术 [36, 37, 38, 39, 40, 41],意图有效地支持代码生成。近期研究表明,大语言模型的输出可能受规格歧义、提示效应与模型偏置的影响 [42, 43]。研究还表明,简单的扰动——例如对提示进行句法变换 [36, 40]、在语义保持的前提下改写指令 [37, 41],以及其他语言修改 [38, 44, 45, 46]——都可能影响模型回答的正确性。即使代码按照生成的测试看起来是正确的,隐藏的行为缺陷仍可能未被检出 [47]。这些发现使人担心完全依赖大语言模型生成的测试作为验证制品,并促使人们更仔细地考察代码生成与测试生成之间的交互。
VIII-C 测试先行与测试驱动开发
软件工程界长期以来倡导测试先行开发与测试驱动开发(Test-Driven Development, TDD),将其作为提高软件质量、减少缺陷的机制。在传统 TDD 中,开发者先于实现编写测试,以确保需求在开发期间被显式捕获并得到验证。TDD 的成功在很大程度上归因于规格(测试)与实现之间的独立性,这减少了确认偏误,并鼓励澄清需求 [48]。
大语言模型的出现挑战了这一假定。在许多实际工作流中,开发者先用大语言模型生成代码,随后要求同一个模型或另一个模型为所生成的代码产出测试。尽管这种“先代码后测试”的工作流很方便,它可能在实现与生成测试之间引入很强的依赖。因为测试以生成的代码为条件,它们可能验证的是实现,而不是预期规格,从而形成一种预言机偏差。尽管关于基于大语言模型的测试生成已有大量研究,相对较少的工作像本文这样研究在实现之后生成测试所伴随的风险。
IX 效度威胁
一项主要威胁源于大语言模型的非确定性:它们在不同执行中可能产出不同的实现与测试套件。为减轻这一威胁,我们尽可能使用低温度设置,并在需要较高温度时把生成重复十次。
我们的发现的可推广性可能受任务、模型与实验设置选择的限制。本研究使用的基准问题,可能并不能完全代表真实世界软件工程项目的多样性与复杂性。工业系统常常涉及更大的代码库、不断演化的需求、领域特定约束以及广泛的人工监督,这些都可能影响生成实现与生成测试之间的交互。
此外,我们的结果基于一组特定的大语言模型与提示策略,其设计旨在反映现实的软件开发工作流。其他提示策略与工作流可能导致不同行为,因而得出不同结论。例如,测试先行生成、迭代精炼、基于智能体的验证,或涉及多个独立模型的工作流,可能产生不同结果,不应假定它们会表现出本工作所识别的同样局限。
X 结论
大语言模型正越来越多地被集成到软件开发工作流中。它们不仅被用来生成代码,也被用来生成旨在验证该代码的测试。尽管这一工作流带来可观的生产力收益,它也提出一个根本问题:在代码之后生成测试,是否会导致测试所验证的是实现,而不是预期规格?
本文对基于大语言模型的“先代码后测试”工作流进行了实证研究,并考察了它对生成测试套件有效性的影响。我们的结果表明,在实现之后生成的测试,常常受到它们所观察到的代码的强烈影响,从而倾向于强化实现假定并忽略缺陷。因此,较高的测试通过率与代码覆盖率并不必然意味着生成的实现符合原始规格。相反,这类测试可能通过认可代码生成期间所采用的同一种解释,提供一种虚假的正确感。
这些发现凸显了大语言模型辅助开发中一项此前未被充分探索的风险:实现与验证之间独立性的丧失。当任务描述含糊或欠指定时,这一问题尤其成问题,因为生成的代码与生成的测试可能收敛到同一种不正确解释。在这类情形中,测试过程未能实现其首要目的,即识别相对于预期需求的行为偏离。
本研究提供了实证证据:在由大语言模型驱动的软件工程工作流中,代码生成与测试生成的顺序是重要的。结果提示,实践者在完全依赖事后由大语言模型生成的测试作为正确性预言机时应保持谨慎,并应偏好在规格、实现与验证之间保持一定分离的工作流。
未来工作可以探索减轻这一风险的技术,包括规格优先提示、独立的测试生成模型、对抗性测试生成,以及人在回路的验证策略。更广泛地说,我们认为,理解多个由大语言模型生成的制品之间的交互,对于构建可信的人工智能辅助软件工程过程将是必不可少的。随着大语言模型在开发工作流中承担更大责任,确保测试仍然是一种独立且有效的质量保证机制,对于实现其潜力至关重要。
署名与许可
本文译文由 智测团队 翻译。原文 On the risk of coding before testing: An empirical study on LLM-based test generation workflow(arXiv:2607.05139)以 CC BY 4.0 许可发布。原作者:Michael Konstantinou、Florian Tambon、Mike Papadakis(单位:SnT, University of Luxembourg,卢森堡)。
CC BY 4.0:https://creativecommons.org/licenses/by/4.0/
Found it useful? Pass it on
Scan with WeChat to open it on your phone and forward it.