引言
大语言模型(LLM)在自然语言处理中表现出了卓越的性能,包括问答、翻译、文本生成并且能够处理大规模数据集,并为通用人工智能开辟了新的可能性。
在代码生成领域,LLM已被用于各种编码的相关任务,包括代码生成、代码评审以及单元测试等任务。
本文以LLM生成单元测试用例为切入点,对LLM生成测试用例的有效性和方法进行了简要探讨。
一、LLM生成测试用例的有效性
1.1 大模型:提升软件测试效率的前沿创新
软件测试是一项至关重要的工作,是确保软件产品质量和可靠性的基石。软件测试有助于在开发生命周期的早期识别和解决问题,从而降低维护成本,从而防止出现更严重的复杂情况。
单元测试的目标是验证每个程序单元是否按预期工作并满足指定的要求。单元的意思是指一段可以独立分离和检查的代码。像写代码一样,单元测试不仅要正确,还要满足其他质量属性,例如可维护性和可读性。
软件测试通常会使用软件测试工具,通过软件测试工具来生成测试用例。目前测试工具的研究已经取得了显著的进展,尤其是通过基于搜索、约束和随机等技术生成单元测试的方法,但仍然存在一些挑战,如生成的测试覆盖率和可读性无法完全满足人们的需求,同时全面覆盖仍然是一个难以实现的目标。在面对这些局限性时,研究人员一直在积极探索创新技术,以提高软件测试任务的效率。在这方面,大型语言模型(Large Language Models,LLM)是目前最有前途的方向之一。
1.2 LLM生成测试用例有效性验证方法
论文《An Empirical Study of Using Large Language Models for Unit Test Generation》为软件测试领域的进展提供了重要的实证研究。该研究以三种生成模型(StarCoder、Codex和GPT-3.5-Turbo)为对象,分析它们在单元测试生成任务中的性能。具体而言,研究采用了两个基准测试,分别是HumanEva和Evosuite SF110(Java版本),并通过对编译率、测试正确性以及覆盖率等方面进行评估,深入探讨了这些LLM在生成测试用例方面的有效性。
第一步
论文首先对焦点方法(focal method)进行检索和排除:
-
E1:仅检索非静态方法,且只在公共类中进行检索;
-
E2:排除以is开头、不带参数且返回布尔类型;
-
E3:排除set开头;
-
E4:以get开头且不带参数;
-
E5:覆盖java.lang.Object(toString(),hashCode()等);
三个标准:
-
I1:public类型的函数;
-
I2:有返回值;
-
I3:具有良好的"javadoc"。其中javadoc是指具有描述或者非空@return标签,并且所有方法的参数具有与@param标签相关联的描述。
第二步
设计相对应prompt和上下文结构,如下:
图一
第三步
对LLM生成的output进行启发式处理来自动修复output中代码的错误:
-
H1:它删除在以下任何模式之后找到的任何代码:"\n\n// {CUT_classname}", "\n```\n\n##",""
-
H2:保留反引号之间的内容,删除反引号前后的所有文本,"```code```";
-
H3:它将从生成的单元测试中删除原始提示;
-
H4:在单元测试中找到包声明,并将其重命名为CUT的包(CUT是被测类);
-
H5:如果缺少包声明,则添加该声明;
-
H6:用integer.parseInt(n)替换大整数常量;
-
H7:通过迭代删除行(从下到上)并添加1-2个大括号来修复不完整的代码;
第四步
对output进行分析,论文用Juint5和JaCoCo来运行测试程序来计算覆盖率和正确性指标。覆盖率分为分支覆盖率(Branch Coverage)和行覆盖率(Line Coverage)。
公式如下:
公式一
公式二
1.4 LLM生成测试用例结果分析
1.编译率结果
如Table 1,我们能够发现,经过H1-H7自动修复后,编译率有明显的提升;在HumanEval数据集上表现最好的是StarCoder,高达70.0%,而其他只有不到一半是可编译的;在SF110数据集上,编译率都不高,最高的StarCoder仅有12.7%;启发式修复后,编译率平均提高了41%,Codex(2K)增幅最大,而启发式方法对StarCoder的作用不大,只提高了6.9%的编译率。
编译错误分析
在HumanEval数据集方面,常出现的编译错误原因是编译器找不到符号、从数据格式转换不兼容等原因;而在SF110数据集方面,常出现的编译错误是编译器找不到符号,或者class是抽象类而无法实例化造成的。
2.测试通过分析
如Table 2,在进行自动修复后,执行了能够通过编译步骤的每个测试。测试正确性方面有两个指标,Correct指的是所有测试方法均能通过;Somewhat Correct指的是至少有通过一个测试方法的测试。
在HumanEval数据集方面,StarCoder表现最好,测试通过率为81.3%,但是ChatGPT的Somewhat Correct的指标高达92.3%。同时增加Codex的Tokens数不能产生更高的正确性。
在SF110数据集方面:表现最好的同样是StarCoder,有51.9%的测试通过率。在Somewhat Correct指标上,Codex(2K)性能最好。与HumanEval相比,所有LLM的两个测试通过率都比较低。
表二
3.测试覆盖率
如Table 3,分别测量了两个数据集上的试的行覆盖率和分支覆盖率,同时比较了Evosuite生成的测试覆盖率进行了比较,并在HumanEval数据集上,添加了手动创建的测试覆盖率。
在HumanEval数据集方面,LLM的行覆盖率在67%~87.7%,分支覆盖率在69.3~92.8%,但是低于手动测试和Evosuit生成的覆盖率。在SF110数据集方面,比HumanEval的覆盖率要差很多,均不到2%,Evosuite覆盖率分别是27.5%和20.2%。
表三
LLM生成测试用例结果分析
本节对比了三种代码生成LLM在单元测试生成方面的能力,根据编译率、测试正确性和覆盖率方面进行了比较,发现尽管LLM无法产生正确的测试,但能够生成一些对输入/输出有用的测试用例。
在HumanEval数据集方面,LLM的能力与当前先进的测试生成工具有比较接近的性能。基于Evosuite的开源项目上,它们的性能很差。虽然启发式方法能够提高编译率,但生成的一些测试还是不能编译。
二、LLM生成测试用例的方法
2.1 概述
本节以论文《Reinforcement Learning from Automatic Feedback for High-Quality Unit Test Generation》中所采用方法进行讲解,主要是微调方面。
文章提出的方法是静态质量指标强化学习(RLSQM),通过使用静态质量指标分析对程序进行评分,将其灌到LLM中,接着训练奖励模型(RM)根据静态质量指标对测试用例进行评分,并使用评分为近端策略优化(PPO)算法提供反馈。来增强LLM能够生成更高质量的测试用例。
2.2 静态质量指标
在前一章节,对生成测试用例的有效性,我们是在编译率、测试通过率以及覆盖率三个方面进行的讲解,这都属于静态质量指标。本节所采用的静态质量指标如下:
图2-1
其中:
-
语法是否正确:根据代码语言的规范,生成的测试用例在语法上应有效;
-
是否有断言;
-
是否有焦点方法的调用;
-
输出的测试用例是否有多余字符;
-
是否生成注释/评论;
-
是否重复断言;
-
是否包含try/catch块、控制语句(if、switch、while)或异常处理;
-
是否包含空测试(例如public void TestMethod(){ })。
2.3 实验设计
数据收集是从GitHub上的至少5星的开源C#项目中选取焦点方法来构建的数据集,只考虑了MSTest框架编写的TestMethods为特色的项目。
如下图是对数据prompt的设计。上下文将被截断来适应模型的上下文长度。
图2-2
LLM的常用的微调方法是监督微调(Supervised Fine-Tuning),使用监督微调能够使得模型能够更好地适应特定任务,从而提高任务性能。
关于静态质量指标的分析,论文中,使用树状定位器解析器(tree-sitter)来分析单元测试属性,确保模型可以生成高质量的测试用例。下图是整个的训练流程。
图2-3
(1)从基础LLM和一组输入提示和高质量单元测试开始,通过标准监督微调(SFT)更新模型权重;
(2)我们使用 SFT 模型生成完成,然后训练奖励模型(RM)来预测质量分数,这些分数由我们的质量分析器自动生成;
(3)我们使用SFT模型权重初始化策略模型(PM),然后对其进行微调以最大化RM预测的奖励。
2.4 实验结果
表中使用个人奖励对RL进行微调后测试集的质量指标。"√"表示应该鼓励的积极特征;"×"表示应该劝阻的负面特征。
与基础模型相比,RL优化模型,使模型提高了21%,并生成了将近100%的语法正确的代码。并且7个指标中的四个指标上优于GPT-4。
强化学习能够将所有质量指标提高到SFT模型之上,表明RLSQM微调能够增强单个质量指标。
图2-4
三、总结与展望
本文主要介绍了LLM生成测试用例的有效性验证以及微调方法。尽管LLM在单元测试领域还处于起步阶段,但已经表现出了巨大的潜力。
当前评价测试用例的好坏主要是编译率、测试通过率、覆盖率等静态质量指标。评价的测试集有两种,一组是HumanEval,另一组是开源库。前者的指标明显高于后者。当前SFT是主流的微调方法,但强化学习也开始融入微调的过程中,能够有效提高模型的性能。
对于测试用例,每一种语言都有各自的测试框架,目前主要是以单语言来进行训练,并未考虑多语言的情况。
LLM还有许多未知领域等待我们去探索,相信在可见的未来,LLM能够有效提高项目研发的效率和质量,成为每个编程人员必备的工具。
四、参考文献
[1] Software Testing with Large Language Model: Survey, Landscape, and Vision: https://arxiv.org/abs/2307.07221
[2] An Empirical Study of Using Large Language Models for Unit Test Generation: https://arxiv.org/abs/2305.00418
[3] Reinforcement Learning from Automatic Feedback for High-Quality Unit Test Generation: https://arxiv.org/abs/2310.02368