这篇文章主要研究了一个非常实际的问题:如何利用人工智能(大语言模型)来帮程序员写“单元测试”(代码的体检报告),并且如何让这些 AI 写的报告既准确又好读。
为了让你更容易理解,我们可以把整个软件开发过程想象成开一家餐厅,把“代码”想象成菜谱,把“单元测试”想象成试菜员。
1. 背景:为什么需要“试菜员”?
在开餐厅(开发软件)时,厨师(程序员)写好了菜谱(代码)。为了确保这道菜没毒、味道对,必须有人先尝一尝,这就是“单元测试”。
- 传统做法:让厨师自己写试菜步骤。但这太累了,而且容易漏掉细节。
- 老式自动化工具:以前有一些机器能自动写试菜步骤,但写出来的步骤像乱码,人类根本看不懂,也不实用。
- 现在的 AI(大语言模型):像 ChatGPT 这样的 AI 很聪明,能写出像人写的、好读的试菜步骤。但是,AI 有时候会“幻觉”(胡说八道),或者写出的步骤有语法错误,导致试菜失败。
2. 核心问题:怎么让 AI 写得更好?
这就好比你想让一个刚入行的试菜员(AI)写出完美的试菜报告,你该怎么做?
- 零样本(Zero-shot):直接命令 AI:“你去写个试菜报告。”(AI 可能会写得一般,因为它没看过你的标准)。
- 少样本(Few-shot):给 AI 看几个优秀的试菜报告作为例子,让它模仿。这就像给实习生看几份满分试卷,告诉他:“照着这个格式和思路写。”
这篇论文的核心就是研究:给 AI 看什么样的“满分试卷”(例子),效果最好?
3. 实验设计:三种“满分试卷”来源
研究人员找了三种不同来源的试菜报告作为例子给 AI 看:
- 人类厨师写的:最专业,逻辑清晰,但可能比较贵(人工成本高)。
- 老式机器写的(SBST):像以前的自动化工具,覆盖面广(能尝到很多角落),但写得像天书,很难读。
- AI 自己写的:用 AI 生成的例子再教 AI。
还有一个关键问题:怎么挑例子?
- 随机挑:像从题库里随便抓几个例子。
- 智能检索:像用搜索引擎,找和当前这道菜(代码)最相似的例子。比如,如果现在要测“红烧肉”,就找以前测“红烧肉”或“炖肉”的例子,而不是找“清蒸鱼”的例子。
4. 主要发现(用大白话总结)
A. 例子从哪里来最重要?
- 人类写的例子是王道:如果你给 AI 看人类写的优秀试菜报告,AI 写出来的报告最准确、覆盖最全面。就像给实习生看大师的手稿,他学得最快。
- 老式机器写的例子也有奇效:虽然它们写得难懂,但如果你用它们来修补那些覆盖率很低的旧菜谱,效果反而出奇的好。因为它们能覆盖很多人类容易忽略的死角。
B. 怎么挑例子最重要?
- “看人下菜碟”最有效:单纯随机挑例子效果一般。最好的方法是智能检索,即同时看“这道菜是做什么的(问题描述)”和“这道菜是怎么做的(代码结构)”,找最相似的例子给 AI 看。这就像教人做红烧肉,你给他看“红烧肉”的教程,而不是“炒青菜”的教程。
C. AI 写的报告能直接用吗?
- 不能直接用,但可以“修”:AI 写的报告经常会有小毛病(比如少个标点、少个引用)。但是,这些毛病都很小,就像试菜报告里少写了一个“盐”字。
- 自动修补很管用:研究人员写了一套简单的“自动修补规则”(比如自动补全缺少的引用),修补后,AI 写的报告通过率非常高(从不到 1% 提升到 80% 以上)。
5. 结论与启示
给程序员的建议(给餐厅老板):
- 不要指望 AI 能完全取代人类写测试。
- 最好的用法是“人机协作”:让 AI 基于人类写的高质量例子,去生成新的测试,专门用来填补那些人类没覆盖到的盲区。
- 不要怕 AI 犯错:只要有一套简单的自动修补流程,AI 生成的测试不仅好用,而且读起来也很顺畅,不会给团队增加太多维护负担。
给研究者的建议:
- 以前大家只关注 AI 写的代码“对不对”(能不能跑通),现在发现,“好不好读”、“方不方便维护” 同样重要。
- 给 AI 提供最相关的例子(通过智能检索),比随便给几个例子要有效得多。
一句话总结
这篇论文告诉我们:教 AI 写代码测试,就像教徒弟做菜。给他看人类大师的菜谱(人类例子)效果最好;如果找不到大师菜谱,用智能搜索找最相似的菜谱(智能检索)也比瞎蒙强。虽然 AI 偶尔会写错字,但只要有个简单的“自动校对”环节,它就能成为帮你完善菜谱的得力助手。
论文技术总结:基于大语言模型与少样本提示的自动化测试套件增强
1. 研究背景与问题定义
背景:
单元测试是软件质量保证的基石,但手动编写测试用例耗时且劳动密集。传统的自动化测试生成方法(如基于搜索的软件测试 SBST)虽然能生成一定覆盖率的测试,但生成的代码往往缺乏可读性、自然性和实用性,难以被开发者直接采纳。近年来,大语言模型(LLM)在代码生成领域表现出色,但现有的研究多集中在零样本(Zero-shot)生成上,且 LLM 生成的测试常存在幻觉(生成看似合理但错误的代码)和非确定性等问题。
核心问题:
- 少样本学习(Few-shot Prompting)的潜力未被充分挖掘:在单元测试生成中,如何利用不同来源(人类编写、SBST 生成、LLM 生成)的示例来指导 LLM 生成更高质量的测试?
- 示例选择策略的影响:在构建少样本提示时,是随机选择示例,还是基于检索(Retrieval-based)选择与当前测试对象(CUT)上下文相关的示例,哪种策略更能提升生成测试的质量?
- 测试套件增强(Test Suite Enhancement):LLM 生成的测试能否有效补充现有的测试套件(包括人类编写的、SBST 生成的或混合的),从而提升整体覆盖率、正确性和可维护性?
2. 方法论 (Methodology)
2.1 实验设置
- 模型:使用 GPT-4o(集成于 GitHub Copilot),因其在开发者中的普及性和过往研究中的优异表现。
- 数据集:
- HumanEval:包含隔离的代码练习题,代表简单场景。
- ClassEval:包含跨文件引用,需要类级别参考,代表更复杂的场景。
- 数据构建:将基准测试转换为
pytest 格式,并构建了三种来源的测试用例数据集:
- 人类编写(Human):基准测试中的原始测试。
- SBST 生成(Pynguin):使用传统搜索工具生成。
- LLM 生成(ChatGPT/GPT-4o):使用零样本提示生成。
- 提示工程(Prompt Engineering):
- 采用 Persona Pattern(角色设定)和 Few-shot Code Example Generation Pattern。
- 示例数量:通过预实验确定每个提示包含 5 个 示例(nexamples=5)效果最佳。
- 提示结构:包含系统提示(定义角色和任务)和用户提示(包含被测类代码及选定的示例)。
2.2 示例选择技术 (RQ2)
研究对比了多种从现有测试套件中选择少样本示例的方法:
- 随机选择:
- 从整个测试套件中随机选择(Random from All)。
- 仅从被测类(CUT)的现有测试中随机选择(Random from Class)。
- 基于相似度的检索选择:
- 问题定义相似度:基于自然语言描述(Problem Definition)的 TF-IDF 和余弦相似度。
- 源代码相似度:基于源代码的相似度。
- 代码 + 注释相似度:结合源代码和文件顶部的自然语言注释。
- 问题 + 代码综合相似度:综合上述两者的得分。
2.3 评估流程与修复机制
为了应对 LLM 生成的测试常出现的语法错误和导入缺失问题,研究设计了一个包含 验证(Validation) 和 基于规则的修复(Rule-based Repair) 的流水线:
- 修复规则:包括添加缺失的
pytest 或 CUT 导入、移除错误的模块导入、移除 self 参数、修复语法错误(如括号缺失)、移除无执行代码的测试等。
- 评估指标:
- 功能正确性:语法正确性、编译通过性、执行通过率。
- 代码覆盖率:行覆盖率(Line Coverage)、分支覆盖率(Branch Coverage)。
- 代码质量:圈复杂度(Cyclomatic Complexity)、认知复杂度(Cognitive Complexity)、测试异味(Test Smells)、可维护性(Maintainability/Technical Debt)。
3. 主要研究问题 (Research Questions)
- RQ1:少样本提示中使用不同来源(人类、SBST、LLM)的示例如何影响生成测试的质量?
- RQ2:基于检索的示例选择技术如何影响生成测试的质量?
- RQ3:使用不同来源的示例如何影响现有测试套件的增强效果(覆盖率提升、质量变化)?
- RQ4:基于检索的选择技术如何影响现有测试套件的增强效果?
4. 关键结果 (Key Results)
4.1 示例来源的影响 (RQ1 & RQ3)
- 正确性:经过规则修复后,所有来源(人类、SBST、LLM)生成的测试在执行通过率上均达到较高水平(约 76%-84%)。SBST 生成的示例在修复前的初始执行通过率最高,但修复后差异缩小。
- 覆盖率:人类编写的示例在生成测试的覆盖率和正确性方面表现最好,提供了最佳的模式供 LLM 学习。
- 测试套件增强:
- SBST 示例在增强低覆盖率的初始测试套件(如 ClassEval 中的 SBST 初始套件)时效果最显著,覆盖率提升幅度最大(例如 ClassEval 分支覆盖率提升 +23.9%)。
- 人类示例虽然初始覆盖率已很高,提升空间小,但最终生成的优化套件覆盖率最高(接近 100%)。
- 结论:SBST 生成的测试对于填补覆盖率空白非常有效,而人类测试对于维持高质量标准更优。
4.2 示例选择技术的影响 (RQ2 & RQ4)
- 正确性:不同的选择技术(随机 vs. 检索)对修复后的测试正确性影响不大。
- 覆盖率:“问题定义 + 源代码相似度”(Problem + Code Similarity) 的检索策略表现最佳。它 consistently 产生了最高的分支覆盖率,特别是在 ClassEval 数据集上。
- 代码质量:选择技术对代码质量(复杂度、异味)没有表现出一致的显著优势,但综合相似度方法在保持高质量的同时提升了覆盖率。
- 随机选择的表现:仅从被测类中随机选择(Random from Class)表现最差,表明仅依赖局部上下文不足以生成多样化的测试。
4.3 代码质量与复杂度
- 圈复杂度:生成的测试套件圈复杂度有所增加,特别是在使用 SBST 示例增强 ClassEval 时,这表明生成的测试逻辑可能更复杂。
- 认知复杂度与异味:人类示例生成的测试认知复杂度较高(逻辑更复杂但可能更符合人类思维),而 SBST 示例生成的测试异味较少。总体而言,LLM 生成的测试在可维护性方面与人类编写的测试相当,未引入过多的技术债务。
5. 主要贡献 (Key Contributions)
- 实证研究少样本学习在测试生成中的应用:系统评估了不同来源(人类、SBST、LLM)的示例对 LLM 生成测试质量的影响,填补了该领域的研究空白。
- 提出并验证了检索增强策略:证明了基于“问题描述 + 源代码”的综合相似度检索策略优于随机选择,能有效指导 LLM 生成高覆盖率的测试。
- 构建了完整的测试增强流水线:结合了 LLM 生成、规则修复和覆盖率优化,展示了如何在混合(Human-AI)代码库中实际部署 LLM 测试生成。
- 揭示了 SBST 与 LLM 的互补性:发现 SBST 生成的测试作为少样本示例,在提升低覆盖率套件方面比人类测试更有效,挑战了“人类测试总是最优”的假设。
6. 意义与启示 (Significance)
- 对研究者的启示:评估 LLM 生成的测试不能仅看正确率和覆盖率,必须纳入可维护性(认知复杂度、异味)等指标。未来的基准测试应包含更复杂的跨文件场景(如 ClassEval)。
- 对从业者的启示:
- LLM 生成的测试不应完全替代人类测试,而应作为增强机制(Augmentation),用于填补现有测试套件的覆盖率空白。
- 轻量级修复(Rule-based repair)足以解决大部分 LLM 生成的语法和导入错误,无需复杂的修复框架。
- 在构建少样本提示时,应优先选择问题描述与代码综合相似度最高的现有测试作为示例,而非随机选择。
- 对于覆盖率较低的旧系统,利用 SBST 生成的测试作为示例来指导 LLM 生成新测试,是一种高效提升覆盖率的策略。
总结:该论文证明了通过精心设计的少样本提示(特别是结合检索策略和多样化示例来源),LLM 能够生成高质量、高覆盖率且可维护的单元测试,有效辅助软件维护和质量保证。
每周获取最佳 computer science 论文。
受到斯坦福、剑桥和法国科学院研究人员的信赖。
请查收邮箱确认订阅。
出了点问题,再试一次?
无垃圾邮件,随时退订。