一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

一种面向随机测试生成工具的冗余检测与去除方法

2022-05-31 17:30:37 来源:中国专利 TAG:


1.本发明涉及一种面向随机测试生成工具的基于生成时信息、测试异味和测试要求的冗余检测与去除方法,属于软件单元测试技术领域。


背景技术:

2.单元测试是软件开发生命周期中必不可少的任务,它验证程序中最小的可测试单元,保证软件质量。但是,软件测试所需的时间往往占整个软件开发时间的一半以上。手动编写高质量的单元测试可以提高开发效率,但费时费力,这种重复和低效的任务有望被自动化单元测试用例生成工具取代。基于java的自动化单元测试用例生成工具使用了不同的测试生成方法,例如基于搜索的测试、基于随机的测试、基于模型的测试,结合符号执行技术的测试生成方法。基于搜索的软件测试使用搜索算法来优化适应度函数和最大化测试目标,进而自动生成单元测试。随机测试生成工具具有可扩展性且易于实施的特点,它从程序的输入空间中随机选择输入,并检查程序对每个输入的行为是否正确。符号执行使用符号值代替具体值作为输入,输出是这些符号的数学表达式,使用符号执行技术能够探索更多不同的程序路径,而将符号执行与测试生成方法相结合的混合方法在一定程度上能够对两种方法取长补短。基于模型的测试依赖于对被测系统或其环境的预期行为进行编码的显式行为模型,并自动生成有用的测试用例,由于测试套件源自模型而非源代码,这类测试通常被视为黑盒测试的一种形式。
3.从多项实证研究结果中可以发现随机测试工具(以randoop为代表)为被测类生成大量的测试用例,但是测试用例数量与质量并不成正比,大多数测试用例无助于提高测试的整体覆盖率、错误检测能力等,因此其中存在着许多冗余。


技术实现要素:

4.发明目的:针对现有技术中存在的问题与不足,本发明提供一种面向随机测试生成工具的冗余检测与去除方法,主要针对随机测试生成工具randoop,在构建测试的不同阶段,结合其特定输入参数的机制、随机选择的方式和衡量测试质量的标准以改进测试生成过程,引入不同的策略来检测和去除过程中存在的冗余,一共采用三个策略来实现冗余的检测与去除,从而缩减测试套件的大小,降低测试成本,提高测试效率和可读性。
5.技术方案:一种面向随机测试生成工具的冗余检测与去除方法,包括基于序列相似度和被测方法特性的优先级选择策略、基于测试异味(重复和无用测试断言语句)的冗余去除策略、基于测试要求(包含分支覆盖情况和变异杀死情况)的冗余用例去除策略。具体包含以下步骤:
6.步骤1,用户给定目标被测类,得到相应的单元测试。
7.步骤2,本发明方法提出的randoop-tsr增量地构建方法序列,结合先前生成的旧测试来生成新测试,并提供了序列输入选择机制。
8.步骤3,randoop-tsr执行自动化生成的方法序列,检查执行结果,并进行反馈,从
而达到避免已知有错或抛出异常的方法序列被继续扩展的目的。
9.步骤4,在获得了可执行的方法序列后,实施基于测试异味的冗余去除策略,检测、过滤和去除重复以及无用的断言语句。
10.步骤5,在获得了可执行的方法序列后,采用基于测试要求的冗余用例去除策略对测试套件进行缩减。
11.步骤6,randoop-tsr将缩减前的可执行方法序列作为原回归测试文件进行输出;缩减后的可执行方法序列作为缩减回归测试文件进行输出;将无法执行的出错的方法序列作为错误揭示(error-revealing)测试文件进行输出,记录一个或多个被测类中存在潜在的错误。
12.所述步骤1中,用户给定目标被测类的名称、源代码文件和编译后的二进制文件,以及相应依赖、时间预算、其他特性的测试参数等;然后用户使用命令行的方式运行工具以得到相应的单元测试。
13.所述步骤2,randoop-tsr增量地构建方法序列,结合先前生成的旧测试来生成新测试,并提供了序列输入选择机制(即,
‑‑
input-selection),该机制控制了如何从所有新生成的测试序列中选择测试的方式,默认为uniform纯随机选择方式,但容易导致选择重复的方法序列进入后续的测试生成过程,出现冗余。基于序列相似度和被测方法特性的优先级选择策略需要用户在运行工具前,提供unduplicated_tests作为
‑‑
input-selection指令的参数,就能够执行该策略的内容;具体实现过程为:
14.21)通过静态分析工具reiminfer提取出的被测类中不能改变数据成员状态的被测方法(observer methods)的名称,并将其保存在文件中,后续该文件将作为一项输入参数。被测方法可以按照其特性被分为能改变数据成员状态的被测方法(状态改变者方法,state-modifier methods)和不能改变数据成员状态的被测方法(观察者方法,observer methods)。然而,如果在测试序列生成的过程中,频繁调用观察者方法会使得创建很多冗余的长序列和单一的对象状态,导致冗余且不利于覆盖率的整体增长。
15.22)成分映射。randoop-tsr会不断地生成多个新产生的方法序列作为候选方法序列,并从这些候选方法序列中挑选一个用于后续的序列扩展过程。成分映射需要提取出当前每个候选方法序列中存在的3个成分,分别是:a)对象类型;b)被测方法名称;c)参数及常量值。将提取出的每个候选方法序列中的3个成分内容分别存入3个列表中,列表中分别包含上述成分的具体内容,并标记出调用的被测方法中的状态改变者方法和观察者方法。
16.23)randoop-tsr会把22)中提到的从多个候选方法序列中选择出的每一个方法序列的相应3个成分存入成分池中,也即成分池中存的是所有之前选择出的方法序列的成分内容。将每次新产生的每个候选方法序列的3个成分与成分池中3个成分的内容作比较,计算每个方法序列成分与相应成分池中各个序列的相应成分的不相似度,然后对3个成分的不相似度做加权,并选择其中最小加权值作为该序列的不相似度结果,进而求得不相似度结果d和序列权重值w;scorei(n)表示当前候选方法序列与池中第i个序列的3个成分的不相似度结果,计算公式如下所示,对象类型的不相似度记为score(object);被测方法的不相似度记为score(method),在计算score(method)时,若池中未出现的被测方法为状态改变者方法(记为m
modifier
)时,则给予该方法相比观察者方法(记为m
observer
)双倍的分数;score(parameter)记作参数及常量值的不相似度;num(diff(n))计算的是存在于当前候选
方法序列的成分列表中,但不存在于成分池中的数量;对应权重a1、b1、c1默认均为1/3。
17.w=2d18.d=min{a1*score(object) b1*score(method) c1*score(parameter)}
[0019][0020]
权重值越大,则序列不相似度越高,相似度越低。当新产生的候选方法序列中调用的被测方法为状态改变者方法且被测方法成分池中未包含时,给予该状态改变者方法相比观察者方法更高的权重。
[0021]
24)根据按照权重的随机算法,从多个候选方法序列中选择一个序列。相似度越低,权重就越高,就更容易被选择。选择出的序列中的3个成分内容将会加入到相应成分池中,并且该序列将会被用于后续的扩展和测试生成过程。
[0022]
所述步骤4,在获得了可执行的方法序列后,实施基于测试异味的冗余去除策略,该策略旨在检测、过滤和去除重复以及无用的断言语句。软件项目中测试异味包含数十种,本发明只选择了对去除当前状态下存在的冗余最便捷有利的测试异味(重复、无用的断言语句),它们的存在可能会影响测试套件的质量、可维护性和可扩展性。在执行变异测试并获得缩减后的测试套件前,先过滤掉所有重复断言,能实现去冗和降低变异测试成本的效果。除此之外,从用例的粒度和断言语句的角度来说,即便对测试套件进行了缩减,但单个用例中仍然会存在无用的测试断言,放弃输出这类断言有助于减小单个测试用例的体量和提升测试在项目代码中发现潜在故障和质量问题的效率。该策略具体步骤如下所示:
[0023]
41)遍历所有可执行序列(这里的可执行序列也即为测试用例)中的测试断言,如果两个用例中包含完全相同的断言语句,则证明断言是重复的,因此可以不让包含重复断言的用例参与后续的变异测试,在降低变异测试成本的同时也达到去除冗余的目的。
[0024]
42)检测每个测试用例中的断言语句。无用断言指的是测试方法中包含的预期参数和实际参数相同的断言语句,利用代码分析框架javaparser来识别出其中无用的测试断言,然后去掉检测出的每个用例中的无用断言语句,从而减小单个测试用例的体量,达到去除冗余的作用。
[0025]
所述步骤5,在获得了可执行的方法序列后,采用基于测试要求的冗余用例去除策略对测试套件进行缩减。首先明确测试要求,包括代码覆盖率和变异杀死率。代码覆盖率衡量了测试覆盖到源代码的比例,包括分支覆盖率、语句覆盖率、方法覆盖率、指令覆盖率、圈复杂度覆盖率等,其中分支覆盖率是最常见的衡量指标,它与其他指标基本是呈正相关的,因此选择分支覆盖率作为覆盖率部分的测试要求;变异杀死率反映了测试杀死植入到源代码中的变异算子的比例,反映了测试检测bug的能力,与覆盖率是两个不同维度的测试要求。该策略把分别满足分支覆盖率和变异杀死率的两部分测试用例子集取并集作为最终的测试套件结果。该策略实现冗余检测与消除的目标是在保证测试要求不变的情况下,获得能够覆盖最大测试要求的最小测试用例集,同时达到去除无用的用例以及测试套件缩减的效果。该策略具体步骤如下所示:
[0026]
51)改写被测类源代码中的if-else代码块,然后为改写后的被测类源代码进行分支插桩,并在分支插桩过程中对所有分支进行编号。
[0027]
52)执行每个用例以获得其覆盖的分支,得到所有用例覆盖的所有分支号(所有分支号用集合br表示),以及每个用例覆盖的分支号。
[0028]
53)求取能够覆盖br的最小用例集,并得到该最小用例集里的每个用例编号。该问题可被看作集合覆盖问题,使用整数线性规划算法求解。整数线性规划(ilp)是一种优化问题,其中变量是整数值,目标函数和方程是线性的。
[0029]
54)为被测类源代码生成方法级别和类级别的变异体,变异体种类参考mujava工具,并通过mujava-aum工具中定义的相应规则来过滤具有等价关系或重复的变异。
[0030]
55)执行每个用例以获得其杀死的变异体编号,得到所有用例覆盖的所有变异体编号,以及每个用例覆盖的变异体编号,这里所有变异体编号用集合mr表示。
[0031]
56)求取能够覆盖mr的最小用例集,并得到该最小用例集里的每个用例编号。该问题可被看作集合覆盖问题,使用整数线性规划算法求解。
[0032]
57)将求取的覆盖最大分支数的最小用例集(记作sb)和求取的杀死最大变异数的最小用例集(记作sm),最终把sb和sm取并集得到缩减后的测试用例集,并输出到文件中。
[0033]
本发明与现有技术相比具有如下优点:
[0034]
(1)本发明提出了三种从不同角度出发的冗余检测与去除策略,分别是序列相似度、测试要求和测试异味,能够在保证整体代码覆盖率、变异杀死率等衡量测试质量的指标基本不变的情况下,大幅度的缩减测试套件的大小,最高能达到90%以上的缩减幅度,降低单元测试的时间和成本,增强了测试套件的可读性、可理解性。
[0035]
(2)本发明改进了现有的流行的随机测试生成工具randoop,在工具构建测试的不同阶段引入冗余去除的模块,为
‑‑
input-selection指令添加了新的参数选项以过滤生成时相似度高的方法序列,并过滤具有重复测试要求的可执行方法序列,以及过滤测试用例中重复和无用的断言语句。由于工具是通过命令行执行的,因此用户只需按照原来的方式运行工具就能得到原测试文件、缩减后的测试文件、揭示错误的测试文件,便于理解和操作,并且简捷高效,提高用户的工作效率。
[0036]
(3)本发明从粗粒度(测试套件)和细粒度(单个测试用例)两个维度考虑,在粗粒度上,选择了实现非冗余的测试要求的测试用例来组成测试套件;在细粒度上,去除了单个用例中存在的冗余的断言语句;减小了单个测试用例的体量,减小了整体测试用例的数量,使得冗余去除更充分和全面,提升了单元测试的质量和效率。
附图说明
[0037]
图1为本发明实施例的randoop-tsr测试生成及冗余去除的总体流程图;
[0038]
图2为本发明实施例的基于序列相似度和被测方法特性的优先级选择策略的流程图;
[0039]
图3为本发明实施例的基于测试异味的冗余去除策略的流程图;
[0040]
图4为本发明实施例的基于测试要求的冗余用例去除策略的流程图。
具体实施方式
[0041]
下面结合具体实施例,进一步阐明本发明,应理解这些实施例仅用于说明本发明而不用于限制本发明的范围,在阅读了本发明之后,本领域技术人员对本发明的各种等价
形式的修改均落于本技术所附权利要求所限定的范围。
[0042]
本实施例提供一种面向随机测试生成工具的基于测试要求和生成时信息的冗余检测与去除方法,缩减测试套件的大小,提高单元测试效率。
[0043]
第一步,由于需要使用命令行的方式运行随机测试生成工具,添加了
‑‑
javafile指令选项用以提供被测类的源代码文件,同时添加了unduplicated_tests作为
‑‑
input-selection指令的参数选项,以在生成时选择与之前成分池中相似度最低的方法序列。用户需要按指定格式给定目标被测类的名称、源代码文件和编译后的二进制文件,以及相应依赖、时间预算、其他特性的测试参数(如,用来保存输出测试文件的文件夹位置)等,从而正确地运行工具。
[0044]
第二步,randoop-tsr持续增量地生成方法序列,结合先前生成的旧测试来生成新测试。
[0045]
第三步,在用户提供了unduplicated_tests作为
‑‑
input-selection参数选项的前提下,会执行基于序列相似度和被测方法特性的优先级选择策略,如图2所示。该策略希望结合被测方法特性和序列相似度从多个候选方法序列中选择出一个与之前选择出的所有方法序列相比的最不相似的序列。序列相似度根据对象类型、被测方法特性、参数及常量值来计算,使用代码分析框架javaparser构建代码的抽象语法树,创建继承于中voidvisitoradapter(javaparser提供的一个不返回任何内容的访问器,并且对其所有访问方法都有一个默认实现)的序列访问器,通过访问methodcallexpr(对对象的方法调用)、stringliteralexpr(文字字符串)、variabledeclarator(变量的声明)、objectcreationexpr(定义对构造函数的调用)等来提取出上述3个成分。计算每个方法序列的3个成分与相应成分池中各个序列的相应成分的不相似度,然后对3个成分的不相似度做加权,并选择其中最小加权值作为该序列的不相似度结果,进而求得不相似度结果d和序列权重值w;scorei(n)表示当前候选方法序列与池中第i个序列的3个成分的不相似度结果,计算公式如下所示,对象类型的不相似度记为score(object);被测方法的不相似度记为score(method),在计算score(method)时,若池中未出现的被测方法为状态改变者方法(记为m
modifier
)时,则给予该方法相比观察者方法(记为m
observer
)双倍的分数;score(parameter)记作参数及常量值的不相似度;num(diff(n))计算的是存在于当前候选方法序列的成分列表中,但不存在于成分池中的数量;对应权重a1、b1、c1默认均为1/3。
[0046]
w=2d[0047]
d=min{a1*score(object) b1*score(method) c1*score(parameter)}
[0048][0049]
由于计算相似度需要耗费一定的时间,而时间预算是由参数提供的,因此需要在工具构建方法序列的过程中动态地调节时间预算,弱化该步骤对测试生成的影响。在此步骤中,候选方法序列是不断生成的,经由该步挑选出的方法序列才会参与后续的扩展、判断可执行等过程。在比较并求取每个候选方法序列与成分池中内容的不相似度之后,进而计算出相应权重,权重越大的序列就越容易被选择。
[0050]
第四步,randoop-tsr执行自动化生成的方法序列,并检查执行结果并反馈,从而
构建可执行的方法序列。
[0051]
第五步,在获得了可执行的方法序列后,实施基于测试异味的冗余去除策略,该策略旨在检测、过滤和去除重复以及无用的断言语句。如图3所示,先遍历所有用例中的断言语句,过滤掉其中包含重复断言的用例,余下的用例才参与后续基于测试要求的冗余用例去除策略的变异测试,降低其成本。除此之外,从单个用例的细粒度来说,用例中仍然会存在无用的测试断言,无用断言具体指的是测试方法中包含的预期参数和实际参数相同的断言语句,利用代码分析框架javaparser来识别asserttrue(junit断言类型,断言一个条件为真)、assertfalse(junit断言类型,断言一个条件为假)、assertnotnull(junit断言类型,断言一个条件为非空值)、assertnull(junit断言类型,断言一个条件为空值)等junit断言中无用的部分,例,以下斜体部分是无用断言的其中两种情况:org.junit.assert.assertnotnull(null);或者是a_class a1=null;org.junit.assert.assertnotnull(a1);而后将检测出的每个用例中的无用断言去掉,从而达到减小单个测试用例的体量和去除冗余的作用。
[0052]
第六步,在获得了可执行的方法序列后,采用基于测试要求的冗余用例去除策略对测试套件进行缩减,同时在保证测试要求不变的情况下,获得能够覆盖最大测试要求的最小测试用例集,进而达到去除无用的用例以及测试套件缩减的效果。测试要求为分支覆盖率和变异杀死率:分支覆盖率衡量了测试覆盖到源代码的分支比例;变异杀死率反映了测试杀死植入到源代码中的变异算子的比例,反映了测试检测bug的能力。该策略把分别满足分支覆盖率和变异杀死率的两部分测试用例子集取并集作为最终的测试套件结果。如图4所示,该策略的具体步骤如下所示:
[0053]
1)改写被测类源代码中的if-else代码块。使用代码分析框架javaparser,创建继承于modifiervisitor(javaparser提供的一个不返回任何内容的访问器,并且对其所有访问方法都有一个默认实现)的if-else代码块访问器,对于一个分支语句,如果它使用了由多个关系表达式构成的布尔表达式来进行分支判断,拆分成多个只由一个关系表达式进行分支判断的分支语句。针对改写后的源代码进行分支插桩,分支包括所有if和switch语句,并在插桩时为出现的每个分支进行编号(编号是integer类型,从1开始计数)。将改写并插桩后的被测类源代码另存为一个新文件。
[0054]
2)执行每个用例以获得其覆盖的分支,得到所有用例覆盖的所有分支号(所有分支号用集合br表示),以及每个用例覆盖的分支号。执行用例的过程使用了外部库中的org.mdkt.compiler.inmemoryjavacompiler等,从而能够将测试用例源码编译为字节码并执行。同时使用自定义的类加载器specialclassloader动态加载被改写的同名被测类。当检测到类的全限定名为被测类名时,该自定义的类加载器specialclassloader将会代替父类加载器对新的插桩后的被测类的字节流代码进行加载。
[0055]
3)求取能够覆盖br的最小用例集,并得到该最小用例集里的每个用例编号。该问题可被看作集合覆盖问题,使用整数线性规划算法求解,求解器采用附带了glpk求解包的scpsolver。整数线性规划(ilp)是一种优化问题,其中变量是整数值,目标函数和方程是线性的。求解目标和约束条件的两个公式如下所示,其中m是测试序列的数量,n是分支总数,a矩阵是测试覆盖分支情况,求解目标是得到最小的用例数量和这些用例的索引,约束条件简单来说就是要求每个已知分支都有至少一个测试序列能够覆盖。
[0056]
求解目标:
[0057]
约束条件:
[0058]
4)为被测类源代码生成方法级别和类级别的变异体,变异体种类参考mujava工具,并通过mujava-aum工具中定义的相应规则来过滤具有等价关系或重复的变异。
[0059]
为源代码生成19种方法级别的变异体和28种类级别的变异体,且针对不同被测类会生成不同数量的变异情况。检测变异代码是否与原代码具有相同效果来判断是否等价,检测两个变异代码达到的变异效果是否相同来判断是否重复。通过去除这些具有等价或者重复的变异,能够在保证变异测试质量的前提下,降低时间和成本,提升效率。
[0060]
5)执行每个用例以获得其杀死的变异体编号,得到所有用例覆盖的所有变异体编号,这里所有变异体编号用集合mr表示,以及每个用例覆盖的变异体编号。通过自定义的类加载器jmutationloader动态加载植入变异体后的同名被测类,其过程为:当检测到类的全限定名为被测类名时,该自定义的类加载器jmutationloader将会代替父类加载器对新的植入变异体的被测类的字节流代码进行加载。
[0061]
6)求取能够覆盖mr的最小用例集,并得到该最小用例集里的每个用例编号。该问题可被看作集合覆盖问题,使用整数线性规划算法求解,求解方式同上述步骤3)。
[0062]
7)将求取的覆盖最大分支数的最小用例集和求取的杀死最大变异数的最小用例集取并集,得到最终的缩减后的测试用例集,并写入到文件中进行输出。
[0063]
第七步,randoop-tsr最终会输出缩减后的可执行方法序列作为缩减回归测试文件(reducedtest*.java);将缩减前的可执行方法序列作为原回归测试文件(regressiontest*.java)进行输出;将无法执行的出错的方法序列作为错误揭示测试文件(errortest*.java)进行输出。
再多了解一些

本文用于企业家、创业者技术爱好者查询,结果仅供参考。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献