基于大语言模型的通用缺陷复现:LIBRO框架的探索与实践
本文档是一篇发表于2023年IEEE/ACM第45届国际软件工程大会(ICSE)的原创研究论文。论文的主要作者是来自韩国科学技术院(KAIST)计算学院的Sungmin Kang、Juyeon Yoon和Shin Yoo。
一、 研究背景与动机
本研究隶属于软件工程领域,具体聚焦于自动化软件测试生成。尽管自动化测试生成技术(如Randoop、EvoSuite)已发展数十年,旨在提高代码覆盖率或生成探索性输入,但它们大多难以实现更具语义性的目标,例如根据自然语言描述的缺陷报告自动生成能够复现该缺陷的测试用例。然而,从缺陷报告生成测试(Report-to-Test)在实际开发中具有重要意义。作者通过实证分析发现,在300个开源Java项目中,由问题报告(Issue)引用提交所添加的测试数量,平均占项目当前测试套件规模的28.4%。这表明开发者经常需要为已修复的缺陷编写回归测试,这是一个重要且重复性高的工作。
现有的缺陷复现技术(如EvoCrash)主要专注于复现程序崩溃(Crash)这类特定缺陷,因为它们可以利用崩溃堆栈轨迹作为隐式预言(Oracle)。然而,大量缺陷报告涉及的是功能错误、逻辑错误等语义问题,而非简单的崩溃。将自然语言描述的预期行为转换为测试预言是一个巨大挑战,导致通用缺陷报告的自动化测试生成问题长期未得到有效解决。
近年来,大语言模型(Large Language Models, LLMs)在代码相关任务上展现出强大能力。受此启发,本研究旨在探索利用LLM来解决通用缺陷报告到测试用例的生成问题。然而,LLM本身无法执行目标程序代码,其生成的测试可能无法编译、执行,或者即使执行失败也未必是目标缺陷的复现。因此,研究的核心不仅在于“能否生成”,更在于“如何可靠地判断和呈现”LLM生成的测试。基于此,作者提出了LIBRO(LLM Induced Bug Reproduction)框架,旨在通过LLM生成测试候选,并借助后处理步骤来识别和筛选出高置信度的缺陷复现测试,从而在减少开发者人工检查成本的同时,提供有效的自动化支持。
二、 研究方法与工作流程
LIBRO框架的工作流程包含四个主要阶段:提示工程(Prompt Engineering)、查询LLM、测试后处理(Test Postprocessing)以及测试选择与排序(Selection and Ranking)。研究在两个数据集上进行评估:广泛使用的Defects4J基准(包含750个可用的缺陷)和作者自行构建的GHRB(GitHub Recent Bugs)数据集(包含31个在LLM训练数据截止日期后提交的缺陷报告,用于缓解数据污染问题)。
第一阶段:提示工程 LLM的性能高度依赖于输入的提示(Prompt)。LIBRO的核心是将缺陷报告转换为一个结构化的Markdown文档作为提示。基本提示包含缺陷报告的标题和描述,并附加特定的指令:“提供一个能复现此问题的自包含示例”,以及一个代码块开始标记和测试方法开头“public void test”,以此诱导LLM生成一个JUnit测试方法。作者系统性地评估了多种提示变体,包括: 1. 示例数量:在提示中加入不同数量(0、1、2)的“缺陷报告-测试用例”示例对。 2. 示例来源:示例来自同一项目内部或其他项目。 3. 额外信息:为崩溃缺陷提供堆栈轨迹;或提供疑似缺陷所在类的构造器信息。 研究最终确定采用包含两个跨项目示例的提示设置,并在每个缺陷报告上执行50次生成尝试(n=50),以获得多样化的测试候选集。
第二阶段:查询LLM LIBRO使用OpenAI的Codex模型(code-davinci-002),通过其API进行查询。温度参数(Temperature)设置为0.7以鼓励多样性生成,最大令牌数设为256。对于每个缺陷报告,LIBRO使用相同的提示生成多个(默认50个)测试方法候选。
第三阶段:测试后处理 LLM直接生成的测试代码通常无法独立编译运行,缺少必要的导入语句和测试类上下文。因此,LIBRO需要进行后处理以使其可执行。 1. 注入到合适的测试类:LIBRO并非创建一个新测试类,而是将生成的测试方法注入到被测程序(SUT)现有的某个测试类中。选择标准是基于词法相似度:计算生成测试与现有各个测试类的令牌交集比例,选择相似度最高的测试类作为注入目标。这模拟了开发者的常见做法,并能自动解决大量依赖(如被测类的导入)。 2. 解析剩余依赖:对于注入后仍未解决的类依赖(如使用的特定类型),LIBRO采用启发式方法:首先在项目源代码中查找完全匹配的公共类;如果找不到或找到多个,则扫描项目中所有源文件的导入语句,选择以目标类名结尾的最常见的导入语句。此外,还添加了处理JUnit断言等常见情况的规则。
第四阶段:测试选择与排序 经过后处理的测试会被执行。一个测试如果能在有缺陷的版本上编译并失败(Fail in the Buggy program, FIB),则成为一个候选。但并非所有FIB测试都是真正的缺陷复现测试(Bug Reproducing Test, BRT)。BRT必须满足:在缺陷版本中失败,在修复版本中通过。LIBRO的目标是识别出高概率的BRT,并以最小化开发者检查工作量的方式排序呈现。 1. 选择(是否呈现结果):LIBRO根据生成的FIB测试之间的“一致性”来决定是否向开发者建议结果。它将具有相同失败输出(错误类型和消息)的FIB测试聚类。其核心假设是,如果多个独立生成的测试表现出相同的失败行为,则LLM对此缺陷的“置信度”较高,成功复现的可能性也较大。通过设置一个一致性阈值(thr,即最大聚类的大小),可以控制结果的精确度(Precision)与召回率(Recall)。例如,设置thr=1(至少有两个测试失败输出相同)可以过滤掉大量非复现的缺陷,同时保留大部分成功复现的缺陷。 2. 排序(呈现哪些结果):对于决定呈现的缺陷,LIBRO对FIB测试进行排序,目标是让BRT尽可能靠前。排序依据三个启发式规则,按判别力从强到弱依次是: * 失败输出与报告的匹配度:测试的失败消息或代码中是否包含了缺陷报告所描述的行为。 * 输出聚类大小:代表LLM生成的一致性程度,聚类越大排名越靠前。 * 测试长度:较短的测试更易于开发者理解,因此优先。 排序算法首先按输出聚类排序,然后在每个聚类内部按上述规则排序。最终呈现时,采用轮询方式从各聚类中依次选取测试,以保持结果的多样性。
三、 主要研究结果
RQ1(有效性): * 缺陷复现数量:在Defects4J的750个缺陷上,LIBRO(使用两个示例,n=50)成功为251个缺陷生成了至少一个BRT,成功率为33.5%。性能在不同项目间有差异,例如在Lang和Jsoup项目上表现较好,而在Closure项目上较差(因其测试结构独特)。 * 提示工程影响:提供示例显著提升了性能;提供堆栈轨迹有助于复现崩溃缺陷;而提供同一项目内的示例有时会导致模型简单复制示例,反而降低性能。生成尝试次数(n)与复现缺陷数量呈对数增长关系,未观察到性能平台期,意味着增加生成数量可能进一步提升效果。 * 基线对比:与最先进的崩溃复现技术EvoCrash相比,LIBRO在60个崩溃缺陷上复现了53个,与EvoCrash相当(54个)。更重要的是,LIBRO还能复现EvoCrash无法处理的198个非崩溃缺陷。与简单的“复制粘贴”基线(直接从缺陷报告中提取代码片段作为测试)相比,LIBRO复现的缺陷数量(251 vs. 36)远超后者,表明此任务远非简单的代码提取。
RQ2(效率): * 资源消耗:处理一个缺陷(生成50个测试)平均需要约444秒(约7.5分钟),其中大部分时间用于调用Codex API(~292秒)。这与其他基于搜索的测试生成技术的常用时间预算(如10分钟)相当。 * 开发者工作量:在一致性阈值thr=1的设置下,LIBRO从570个至少有一个FIB测试的缺陷中,筛选出350个缺陷进行建议。在这350个中,有219个确实被成功复现,精确度达62.6%,同时召回率达87.3%(219/251)。这表明选择机制有效过滤了非复现缺陷。在排序方面,对于这350个被选中的缺陷,LIBRO排名第一的测试就是BRT的比例(Acc@1)为42.6%(149/350);检查前5个测试就能找到BRT的比例(Acc@5)为56.9%(199/350),占所有成功复现缺陷的79.3%。与随机排序基线相比,LIBRO的排名策略在各个指标上均更优,减少了开发者需要检查的非BRT测试数量(Wasted Effort)。
RQ3(实用性): * 在新数据上的泛化能力:在GHRB数据集(31个近期缺陷)上,LIBRO成功复现了10个缺陷,成功率为32.2%,与Defects4J上的结果相近。这有力地证明了LIBRO的能力并非源于对训练数据的简单记忆(数据污染),而具有一定的泛化性。 * 启发式规则的一致性:在GHRB数据集上,成功复现的缺陷其最大输出聚类大小(max_output_clus_size)普遍大于未成功复现的缺陷,这一模式与Defects4J一致,表明用于选择和排序的启发式规则在新数据上依然有效。 * 案例分析:论文展示了成功和失败的案例。成功的案例显示LIBRO能够理解自然语言描述(如特定语言环境下的字符串比较问题)并合成出正确的测试。失败的案例主要源于测试依赖外部文件或复杂的项目特定测试基础设施,这是LIBRO当前能力的局限。
四、 结论与价值
本研究提出并系统评估了LIBRO框架,首次证明了利用大语言模型自动化生成通用缺陷报告对应测试用例的可行性。LIBRO不仅在Defects4J基准上实现了33.5%的缺陷自动复现率,更重要的是,它通过后处理、选择和排序机制,能够以较高的置信度识别出成功的复现,并将有效的测试优先呈现给开发者,从而显著降低其人工检查成本。
科学价值:本研究将LLM的应用从代码生成、补全等任务,拓展到了更具挑战性的“语义驱动”测试生成领域。它揭示了LLM在理解自然语言缺陷报告和生成针对性测试方面的潜力,并提出了一个处理LLM输出不确定性、提升其结果可用性的系统化框架。同时,研究中对提示工程、生成数量与效果关系、以及结果可靠性指标的深入分析,为后续相关研究提供了重要参考。
应用价值:LIBRO有潜力集成到实际的软件开发工作流中。当开发者收到一个缺陷报告时,LIBRO可以自动运行,尝试生成并推荐一个或多个复现测试。这不仅能直接辅助开发者快速编写回归测试,还能为自动化调试、定位技术提供可执行的测试用例,从而激活一系列依赖于测试的自动化软件工程工具。
五、 研究亮点
六、 其他有价值的讨论
作者对LIBRO的失败案例进行了手动分析,归纳了主要失败原因:需要项目特定的测试辅助函数(最常见)、缺陷报告质量低、LLM误解预期行为、依赖外部资源以及生成长度不足。这为未来改进指明了方向,例如引入项目上下文学习(In-context Learning)或微调(Fine-tuning)来适应特定项目的测试模式。
此外,论文还分析了缺陷报告中包含代码片段的情况,发现LIBRO生成的测试中有81%的令牌与报告中的代码片段重叠,但同时LIBRO也能从无代码片段的报告中成功合成测试。这表明LIBRO兼具了从报告中提取代码元素和根据自然语言描述合成代码的双重能力。
这项研究为利用大语言模型推进自动化软件测试,特别是解决长期存在的测试预言问题,迈出了坚实且富有启发性的一步。