AI智能总结
基于大模型的测试断言生成技术 房春荣南京大学 演讲嘉宾 房春荣 南京大学副教授 博士,南京大学软件学院准聘副教授、特聘研究员,博士生导师,紫金学者,CCF高级会员,系统软件/容错计算专委会委员,主要从事智能软件工程研究(BigCode&AITesting)。主持国家自然科学基金项目3项,国家重点研发项目骨干2项,教育部产学合作协同育人项目3项,横向科研项目若干。在CCF-A会议/期刊发表论文40余篇,获得国际会议最佳论文1项,申请发明专利10余项,部分成果在华为、百度等知名企业应用。曾担任AST、AIST等国际会议程序委员会共同主席,多次担任国际顶级会议程序委员会委员及顶级期刊审稿人,并多次获得杰出审稿人。参编多项软件工程和工业APP相关国家、省、团体标准。获2022年国家级教学成果奖,CCF TCFTC2021年软件测试青年创新奖,2020国家级一流本科课程、2018国家精品在线开放课程《软件测试》。 1.研究背景2.单元测试生成和修复3.单元测试的断言问题 目录 ①初步探索:面向单元测试场景的大模型断言生成能力②检索角度:基于混合检索增强的单元测试断言生成③训练角度:基于检索生成协同增强的单元测试断言生成 4.应用验证 5.总结与展望 研究背景大语言模型和单元测试基础PART 01 研究背景-单元测试与测试断言 单元测试:一种被广泛接受的甚至是强制性的开发实践 研究背景-单元测试生成方法存在的主要问题 n以大模型会话迭代为主要框架的代表性方法充分利用了大模型的语义理解和代码生成能力, n以CODAMOSA为代表的算法,计算资源的开销主要取决于选取的传统测试方法,大模型作为辅助工具来改进传统测试方法 研究背景-单元测试生成方法存在的主要问题 n生成无效测试用例: Ø大型语言模型(LLMs)可能在上下文不足的情况下生成无效的测试用例,导致编译错误。这意味着生成的测试用例无法成功运行,影响测试过程的有效性。 n缺乏测试和覆盖反馈: Ø缺乏详细的测试反馈和覆盖率信息可能导致生成的测试用例在运行时出现错误,并且覆盖率低。这意味着生成的测试用例可能未能充分测试目标代码,从而降低了测试的全面性和有效性。 n重复抑制问题: Ø现有方法中,LLMs可能会陷入自我修复或再生成尝试的重复循环,导致生成过程低效。即模型在面对生成错误时,可能会不断尝试修复同样的错误而无法前进,从而浪费计算资源和时间。 研究背景-单元测试生成方法存在的主要问题 n基于LLM的单元测试生成的局限性: ØEvoSuite缺乏深入理解源代码的能力,因此复杂的前提条件缩小了基于搜索的测试生成方法的适用范围。 Ø尽管LLM在理解语义信息和推理生成能力方面表现出色,但生成的测试用例中不可避免地存在编译错误和运行时错误。如果这些错误能够得到修复,LLM生成的测试用例质量将大大提高。 研究背景-自动断言生成方法存在的主要问题 n手动编写单元测试的劳动密集性: Ø编写测试断言通常非常耗时且劳动密集,需要测试专家手动插入测试输入(如前缀)和测试输出(如断言)。 n现有方法的局限性: Ø基于深度学习(DL)的方法通常需要大量的训练数据,并且可能在处理特定任务时表现不佳。Ø依赖于从现有数据中检索相关的测试断言,可能会受到词汇匹配的限制,难以生成语义上有意义的断言。Ø许多现有方法没有采用联合训练策略,导致检索器和生成器之间缺乏协同优化,无法充分利用各自的优势来生成更准确的断言。Ø许多现有方法在有限的训练数据上表现不佳,难以生成高质量的断言。Ø现有使用LLM进行单元测试生成的技术的有效性并没有系统的比较研究。 单元测试生成和修复PART 02 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n生成阶段:是TestART方法的核心步骤,旨在利用大型语言模型(LLM)生成初始的单元测试用例。通过这一阶段,TestART可以自动化生成测试用例,从而减少人工测试的工作量,并提高代码覆盖率。生成阶段的成功执行依赖于有效的上下文预处理和模型提示设计,以充分发挥LLM的潜力。 n修复阶段:修复部分介绍了一种通过联合训练来改进检索增强的深度断言生成方法(AG-RAG),AG-RAG结合外部代码库和预训练语言模型,解决了以前方法中的技术局限,在所有基准和指标上显著优于现有的断言生成方法,大幅提高了准确性和生成唯一断言的能力。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n生成阶段步骤 1、被测代码预处理 n代码清理与压缩:在生成阶段之前,源代码需要经过预处理,以确保LLM聚焦于代码的关键部分。 清理步骤: •去除注释:移除所有代码注释,以防止注释内容与代码逻辑的不一致导致LLM产生幻觉。 •删除多余空行:精简代码结构,提升模型处理效率。 上下文压缩: •仅保留焦点方法的完整方法体,其他非关键方法仅保留其方法签名。 •保留必要的类变量和常量以维持代码的结构和功能完整性。 n变量和方法信息提取: •提取所需的变量和方法信息,包括方法签名、起始和结束行号、变量名和数据类型。 •提取的信息用于构建模型提示,指导生成阶段的测试用例设计。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n生成阶段步骤 3、处理生成的初始测试用例 2、调用大模型生成初始测试用例 n提示设计与模型调用: •对生成的测试用例进行初步检查,识别并标记编译错误和语法错误。•修正简单的语法问题,确保测试用例在编译器中通过基础验证。 •设计特定的提示以激发LLM生成测试用例的能力。•提示内容包括代码上下文、预期行为描述以及已知测试条件。•利用OpenAI的ChatGPT-3.5,通过API接口生成初始测试用例。 n生成的初始测试用例(𝑇!): •ChatGPT-3.5生成的初始测试用例被称为𝑇!。•𝑇!包含对目标代码的多样化测试,包括基本功能测试和边界条件测试。 n生成结果记录与分析: •记录生成测试用例的数量、类型和初步结果。 •分析生成的测试用例覆盖范围及其在真实场景下的有效性。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复n生成阶段步骤 4、准备进入修复阶段 ü利用提示注入优化生成 n错误标记与修复策略准备: n提示注入策略: •标记测试用例中的编译和运行时错误,准备进入修复阶段进行详细修复。•应用模板修复策略,自动修复简单错误,减少修复阶段的工作量。 •使用修复后的测试用例作为提示输入,防止LLM在后续生成中出现相同错误。•提示注入能有效减少模型的重复抑制问题,提高生成用例质量。 n提示优化的效果: n生成-修复协同进化的准备: •修复后的提示能够引导LLM在生成新用例时避免已知错误,并优化测试覆盖率。•实验证明,经过提示优化的生成阶段能显著提高生成用例的通过率和覆盖率。 •在生成阶段结束时,确保所有初步生成的测试用例已准备好进入修复阶段。 •修复后的代码作为新一轮生成的基础,进行迭代优化。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n修复阶段步骤 1、编译与执行 n把测试代码的编译和执行分开为两个步骤进行,这样做的目的是为了更准确地定位问题所在,针对不同类型的错误进行分类处理,并采用对应的修复模板。 2、错误代码定位与信息提取 n通过分析Maven编译时的日志来定位问题。日志包含了详细的错误信息、错误发生的代码位置以及相关的警告信息。对于运行错误,本方法通过分析报错时输出的堆栈追踪信息来定位问题。 n堆栈追踪信息详细包含了异常的类型、发生位置(包括类名、方法名和行号等)以及导致异常的方法调用链。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n修复阶段步骤 3、模板修复 n本发明专注于修复生成的测试用例中出现的编译错误、断言错误以及运行时错误。本发明的修复过程更注重测试用例的内部逻辑和预期行为,确保代码的每个部分都能正确运行。 Ø模板一、导包错误模版 n发生编译错误后,如果错误原因为未找到符号,且在详细错误信息中是由于找不到类符号引起的,那么就认为是导包错误导致的编译错误。Ø首先索引测试项目、JDK和所有第三方依赖的JAR包,以获取在测试期间所有可访问的Java类的完全限定类名(例如,java.util.HashMap)。Ø从详细错误原因中提取缺失的类名,并从索引中找到该类的完全限定类名,然后进行导入。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n修复阶段步骤 Ø模板二、布尔类断言修复 n当在测试用例中使用assertNull方法或者assertTrue方法进行断言时,如果测试失败,意味着被检查的对象与预期矛盾。在这种情况下,将assertNull更正为assertNotNull,assertTrue更正为assertFalse是一种快速修复策略。相反,如果在断言中使用assertNotNull或assertFalse测试失败,则将assertNotNull更正为assertNull,assertFalse更正为assertTrue。 Ø模板三、相等类断言修复 n在测试用例中使用assertEquals方法进行断言时,通常需要比较两个值是否相等。 n使用正则表达式来提取测试报告中的预期值和实际值。n对提取出的实际值进行处理,去除多余的括号和特殊字符,并根据实际值的类型和格式,构造相应的替换字符串。n使用替换字符换将assertEquals中的第一个参数替换为实际值。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 Ø模板四、插入异常处理 n当测试用例的某行代码抛出异常时,通过插入异常处理语句,可以捕获这个异常,达到修复的目的通过使用try-catch语句包裹可能抛出异常的代码行,并在catch块中处理预期的异常类型。 Ø模板五、增加捕获语句 n在某些情况下,现有的异常处理语句可能无法完全覆盖代码执行过程中实际抛出的所有异常类型。为了进一步提高测试用例的健壮性,添加catch语句可以确保原有的异常处理逻辑保持完整,同时避免修改引入新的错误、扩大了异常处理的覆盖范围,使测试用例能够应对更多的错误场景。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n修复阶段步骤 4、大模型修复 图大模型修复错误反馈模板 n在模板修复失败的情况下,本方法采用大模型修复作为补充手段,以进一步提高测试代码的修复成功率。大模型修复的基本思路:将模板修复失败的错误信息反馈给大模型,让其分析错误原因,并尝试生成修正后的测试代码。 提示模板主要由三部分组成: Ø错误提示:告知大模型先前生成的测试代码存在断言错误或者运行时异常,需要进行修正。Ø错误信息:将出错的代码行以及相关错误信息填充到提示中,为大模型提供错误定位和分析的线索。Ø修复要求:明确要求大模型修改测试代码,并以Java代码块的形式输出完整的测试代码。 单元测试生成-基于提示引导和动态反馈的大模型测试用例生成和修复 n修复阶段步骤 5、覆盖信息反馈 n该环节的主要目的是计算第三个环节中输出的测试用例Tp在源代码焦点方法上的覆盖率,并将测试用例的覆盖率信息反馈给大型语言模型,引导其生成下一轮的增量测试用例。 ①计算覆盖率 Ø使用OpenClover工具的Maven插件来计算覆盖率。 Ø清理项目以确保分析的准确性Ø利用OpenClover插件的setup目标初始化覆盖率数据收集环境。Ø执行项目的测试用例集,收集测试过程中被执行的代码行和分支的信息。Øaggregate目标用于整合所有单元测试的覆盖率信息。Øclover目标生成最终的覆盖率报告。②构建反馈提示 自动断言生成-②基于混合检索增强的单元测试断言生成 n研究问题: RQ1:TestART生成的测试用例在正确性方面与基线方法进行比较RQ2:TestAR