智能AI
morning
Coding agent写测试集体失败!AI代码合格率被高估一倍
2026-11-13
1 阅读
约10分钟阅读
新智元
字号:
新智元报道 Coding Agent写代码的能力越来越强,写测试的能力也在同步提升。从为函数补单元测试、为GitHub Issue编写复现用例,到为整个代码仓库构建回归测试,Codex、Claude Code等前沿Coding Agent已经能够浏览仓库、修改实现,并借助执行反馈不断修正测试。 测试的地位也随之变化:它不仅是软件质量的保障,还越来越多地充当Agent自我验证的依据、代码评审的证据,甚至强化学习中的奖励信号。 测试写得好不好,直接决定了这些下游环节能否信任它的判断。 那么,怎样才算一份好的测试? 目前主流的测试生成Benchmark通常采用单一参考评测(Single Reference Evaluation):生成的测试只要在原始代码上失败、在一份标准答案(Gold Solution)上通过,就被视为成功。 问题在于,同一个需求往往存在多种正确实现,也存在许多看似合理却暗含缺陷的错误实现。 一份测试可能恰好「认得」标准答案,却放过了真正有Bug的代码;也可能把标准答案的实现细节当成需求本身,把其他完全正确的写法拒之门外。只看一份参考答案,测试质量很可能被高估。 近日,南京大学刘佳恒老师团队提出了新的测试生成Benchmark TestPrism,包含来自17个来源的300个测试任务和3000个候选实现,每个任务都配有经过验证的正确与错误实现面板,并以Joint Success Function(JSF)作为核心指标:测试必须在原始代码上失败、接受所有正确实现、拒绝所有错误实现。 研究发现:在14种Coding Agent配置中,最强配置的JSF只有28.00%,而它在单一参考评测下的成功率达到59.67%——超过一半通过参考答案的测试,换一批实现就不再可靠。 研究进一步对286条失败轨迹进行专家标注,归纳出3大类、7种测试生成错误机制,并提出TestHelix框架,通过异构合成、同伴交叉验证与递归自我改进,在相同推理预算下将JSF提升11.67至12.00个百分点。 论文:https://doi.org/10.48550/arXiv.2610.12289 研究数据与代码:https://github.com/TestPrism/TestPrism 测试评测缺了什么? 测试生成评测并不是新问题。 已有Benchmark覆盖了不同粒度的任务:TestGenEval、CLOVER和MultiFileTest关注函数、文件或多文件级别的测试编写,SWT Bench和TDD Bench Verified则把测试生成带到真实代码仓库,要求测试复现GitHub Issue中描述的问题。 它们普遍沿用一种成功标准:测试在修复前失败(Fail),在参考修复后通过(Pass),即所谓的Fail-to-Pass。 这一标准简洁、可执行,但隐含了一个假设:只要测试能区分「修复前」和「参考修复后」两个状态,它就足以判断任意实现是否正确。现实中,这个假设很难成立。 一方面,测试可能遗漏关键输入或只做了很弱的断言,参考答案能通过,有缺陷的实现同样能通过; 另一方面,测试可能过度依赖参考答案的具体写法,比如固定的内部函数名、输出格式或中间状态,导致其他同样满足需求的实现被误判为错误。 OmniCode、SWE Mutation等工作开始引入实现变体,但主要考察测试能否拒绝错误变体,仍然缺少对「接受正确替代实现」这一侧的系统评测。 表1|现有测试生成Benchmark的评测范围与评测目标对比(原论文Table 1) 因此,论文提出的核心问题是:How robust is the evaluation of generated tests to variation across implementations? 也就是,当实现方式发生变化时,对测试质量的评价还站得住吗?一份可靠的测试,应当像棱镜一样把同一需求下的不同实现区分开来:对正确实现保持宽容,对错误实现保持敏感。 为每个任务配备一组正确与错误实现 为了回答这个问题,研究团队构建了TestPrism。与只提供一份参考答案不同,TestPrism为每个测试任务配备了一个候选实现面板(Candidate Panel):1份参考实现、4份正确的替代实现,以及5份错误实现。生成测试时,面板对Agent完全隐藏;评测时,测试需要在原始代码和面板中的每一份实现上分别执行。 图1|TestPrism的构建与评测流程(原论文Fig.1) 整个构建过程分为四步。 第一步:任务筛选与适配 研究团队从17个公开Benchmark中收集任务,包括广泛使用的SWE-bench系列和Terminal-Bench系列,以及SWE PolyBench、SWE rebench、EvoEval、USACO、AlgoTune等,覆盖仓库维护、函数规格演化、竞赛编程与数值优化等场景。入选来源都需要具备可追溯的测试来源和有据可查的验证流程。 随后,适配器将不同来源的任务统一转换为Harbor的任务格式,同时保留原始需求、初始代码状态、验证器、参考实现、依赖、服务与执行限制。 第二步:任务选择 团队使用三个指标筛选任务:参考实现的有效代码行数(Solution Size)、测试函数或检查项的数量(Test Count),以及每个被修改文件对应的测试数量(Test Density)。 筛选阈值根据每个来源自身的分布校准,并通过来源配额平衡代表性。最终TestPrism共包含2000个任务,其中1700个划为训练集,用于后文TestHelix的策略优化;300个作为测试集,训练集与测试集互不重叠。 第三步:候选实现生成与验证 在生成候选实现之前,团队首先对每个任务的原有验证器进行复核:它必须在初始状态下失败、在参考实现上通过。 两位具有开发经验的专家独立评估任务需求与验证器,检查是否存在对参考实现的过拟合或覆盖缺口,意见不一致时讨论澄清,仍存疑的任务直接剔除(Cohen's κ = 0.68)。 候选实现本身由不同的Coding Agent和不同能力的模型实际求解任务得到。与传统变异测试(Mutation Testing)人为注入缺陷不同,这种方式能够同时捕获真实存在的替代解法,以及Agent在解题过程中自然产生的错误。 团队移除空提交、完全重复和无法应用的补丁后,在干净环境中运行原有验证器:所有检查都通过的标记为正确实现,任意一项检查失败的标记为错误实现。这些标签在后续评测中保持固定。 第四步:多样性过滤与任务转换 如果4份正确实现只是参考答案的轻微改写,面板就失去了意义。 因此,团队对正确实现组要求满足平均AST距离标准;对错误实现组,未通过的检查项集合不同即视为多样,集合相同时还需额外满足AST Jaccard距离检查。面板通过反复生成与替换,直到两组同时满足多样性要求。 最后,测试生成适配器将每个编程任务转换为一份测试编写契约:Agent需要根据原始需求,在指定目录中提交测试、Fixture和一个可执行的入口脚本。 数据概览 TestPrism测试集的300个任务覆盖Python、JavaScript/TypeScript、Java、C/C++和Go等六种语言,来自67个代码仓库和项目,包含3
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱