system: [SYSTEM]

user: 2. 结合数据流约束的变异测试用例生成方法 本文的方法关注变异语句中变量的定义和使用，考虑变异语句所依赖的数据流约束，使用了一种新的适应度函数模型，逐步引导测试用例过程。首先，将控制流约束和数据流约束结合起来，提供了充分的代码覆盖，共同构建适应度函数模型；然后，使用遗传算法，根据遗传算法“优胜劣汰”的进化特点，依据测试用例的适应度自适应调整搜索方向；最终高效地生成变异测试用例。图1为结和数据流约束的变异测试用例生成方法。如图1所示，本方法由适应度函数建模和测试用例生成两大部分组成。 适应度函数建模部分开始于被测试程序，分别根据程序控制流图CFG (Control Flow Graph)和程序数据流图DFG (Data Flow Graph)计算得到控制流约束函数 c f _ c o n s t r a i n t ( X ) 和数据流约束函数 d f _ c o n s t r a i n t ( X ) ，然 图1. 方法流程图 后组合二者构造出适应度函数 f i t n e s s ( X ) ；测试用例生成部分将用例生成问题转化成了适应度函数 f i t n e s s ( X ) 的优化问题，使用遗传算法优化适应度函数，通过计算每一个测试用例的适应度值，评估用例的优劣，指导对用例的搜索朝着最大化目标分支覆盖的方向，逐渐将测试集收敛至搜索空间的最优点，直至得到最终测试用例。 2.1. 适应度函数建模 适应度函数是基于搜索的方法的核心，它引导测试用例生成过程朝着搜索空间中适应度最好的领域进行，直接决定着搜索结果的好坏。本文的方法改变以往采用控制流约束建立适应度函数模型的思想，将控制流约束和数据流约束结合起来，采用分支函数叠加法建立适应度函数模型，根据个体适应度值指导评价测试用例并指导其选择和进化。适应度函数建模部分如图2所示，分3个主要步骤完成：1) 构建控制流约束函数 c f _ c o n s t r a i n t ( X ) ；2) 构建数据流约束函数 d f _ c o n s t r a i n t ( X ) ；3) 建立适应度函数模型。 1) 构建控制流约束函数 c f _ c o n s t r a i n t (X) 控制流约束用于满足可达性条件，其计算依赖于被测程序的CFG和内部结构。首先分析CFG上变异语句的逼近水平，然后根据变异语句所在分支的谓词表达式计算分支距离，最后将逼近水平和分支距离线性叠加构造出控制流约束函数。 逼近水平用来度量测试用例如何覆盖目标变异语句，表示测试用例X的执行路径与目标变异语句的偏离程度，记作 a p p r ( X ) ，它是根据未被执行的目标变异语句的控制依赖结点的数量计算的。举例说明，程序1是示例程序，图3是程序1的控制流图。假定语句4是程序1的目标测试语句，给出三组不同的输入数据： i 1 = ( 1 ， 2 ， 3 ) 、 i 2 = ( 5 ， 6 ， 6 ) 、 i 3 = ( 10 ， 3 ， 10 ) ，相应的穿越路径为 P ( i 1 ) = { 1 ， 2 ， 5 ， 6 ， 7 } 、 P ( i 2 ) = { 1 ， 2 ， 3 ， 5 ， 6 ， 7 } 和 P ( i 3 ) = { 1 ， 2 ， 3 ， 5 ， 6 ， 7 } 。在这三组不同的测试数据中， i 2 和 i 3 都要执行条件语句3，而 i 1 则在执行完条件语句2之后偏离目标语句4所在的分支，所以测试数据 i 2 和 i 3 比测试数据 i 1 的适应度要好。因此，分别定义 i 1 、 i 2 和 i 3 的逼近水平为： a p p r ( i 1 ) = 1 、 a p p r ( i 2 ) = 0 和 。 分支距离用来评估目标分支被选择的远近程度，表示使目标分支条件为真或假的满足程度，记作 d i s t ( X ) ，它是根据目标变异语句所在分支的条件语句计算的，具体计算表达式如表1所示 [ 12 ] 。 d i s t ( X ) 越小，测试用例的执行路径对目标变异语句的覆盖程度越好。 控制流约束函数记为 c f _ c o n s t r a i n t ( X ) ，定义 c f _ c o n s t r a i n t ( X ) 为 a p p r ( X ) 和 n o r m a l i z e ( d i s t ( X ) ) 的和，如式(1)所示： c f _ c o n s t r a i n t = a p p r ( X ) + n o r m a l i z e ( d i s t ( X ) ) (1) 其中： n o r m a l i z e ( d i s t ( X ) ) 为标准化分支距离，如式(2)所示： 图2. 适应度函数建模示意图 图3. 程序1的控制流图 Program 1. Sample program 程序1. 示例程序 Table 1 Branch distance calculation tabl 分支条件 真分支 假分支 a == b 0 abs (a − b) a != b 0 1 a 0 abs (a − b) + k a <= b 0 Abs (a − b) a > b 0 abs (a − b) + k a >= b 0 abs (a − b) a || b min(dist(a)，dist(b)) dist (a) + dist (b) a && b dist(a) + dist(b) min(dist(a)，dist(b)) 表1. 分支距离计算表 n o r m a l i z e ( d i s t ( X ) ) = 1 − 1.01 − d i s t ( X ) (2) 控制流约束函数 c f _ c o n s t r a i n t ( X ) 的值越小，说明测试用例越满足必要性条件；反之，若控制流约束函数 c f _ c o n s t r a i n t ( X ) 的值越大，则说明测试用例越偏离必要性条件。 2) 构建数据流约束函数 d f _ c o n s t r a i n t (X) 数据流约束用于表示测试用例的执行路径对目标变量定义——使用路径的覆盖程度，由变异语句中变量的定义——使用路径覆盖定义。注意，构造DFG时，CFG中的结点、边和所有路径都在DFG中保留，CFG中的结点对应于DFG中的基本块。计算数据流约束时，首先由DFG计算得到变异语句变量的定义表和使用表，然后将定义表和使用表信息合并得到定义——使用表，最后根据定义——使用表计算数据流约束。 数据流约束函数记为 d f _ c o n s t r a i n t ( X ) ，定义其计算如式(3)所示： d f _ c o n s t r a i n t ( X ) = 1 − d e f − u s e ( X ) ∑ i = 1 M d e f − u s e (3) 其中： d e f − u s e ( X ) 为测试用例的执行路径覆盖目标变量的定义——使用对数量；M为测试用例集的规模。若数据流约束函数 d f _ c o n s t r a i n t ( X ) 的值越小，即 d e f − u s e ( X ) ∑ i = 1 M d e f − u s e 的值越大，则测试用例的执行路径提供的代码覆盖越充分；反之，若数据流约束函数 d f _ c o n s t r a i n t ( X ) 的值越大，即 d e f − u s e ( X ) ∑ i = 1 M d e f − u s e 的值越小，测试用例的执行路径提供的代码覆盖越不充分。 3) 建立适应度函数模型 f i t n e s s (X) 建立合适的适应度函数模型是本文方法的关键，适应度作为测试用例优劣的衡量标准，指导测试集的进化和测试用例的选择。适应度函数记为 f i t n e s s ( X ) ，将其定义为控制流约束函数和数据流约束函数的线性叠加，如式(4)所示： f i t n e s s ( X ) = a ∗ c f _ c o n s t r a i n t ( X ) + b ∗ d f _ c o n s t r a i n t ( X ) (4) 其中：a、b为控制流约束函数和数据流约束函数的权重系数，其定义域均为 ( 0 ， 1 ] 且 a + b = 1 。 X包含全部测试用例是个体适应度函数 f i t n e s s ( X ) = 0 的充要条件。由于控制流约束函数 c f _ c o n s t r a i n t ( X ) 越小，测试用例越满足可达性条件，数据流约束函数 d f _ c o n s t r a i n t ( X ) 越小，测试用例的执行路径提供的代码覆盖越充分。所以，个体适应度函数 f i t n e s s ( X ) 越小，则测试用例的执行路径与目标变异语句间的距离越小，且对变异语句中变量的定义——使用路径覆盖越充分。因此，可将测试用例生成问题可转换为适应度函数 f i t n e s s ( X ) 的最小化问题。 2.2. 测试用例生成 为了提高生成测试用例的效率，本文方法将测试用例生成问题转换成了适应度函数 f i t n e s s ( X ) 的最小化问题，并使用遗传算法解决。根据适应度值动态调整测试用例的生成过程，提高其质量并且减少测试冗余。 测试用例生成过程开始于随机法生成的初始用例集，然后按照适应度函数 f i t n e s s ( X ) 计算初始用例集中各用例的适应度，评估用例的优劣；种群进化时，选择出优良个体来参与交叉、变异操作得到新一代用例集，最后判断终止条件是否满足，若满足，则选择出目标用例，若不满足，则依据个体适应度逐渐将用例集收敛至搜索空间的最优点，不断进化，直至生成最优测试用例。具体流程如图4所示。 图4. 测试用例生成流程图 本方法生成测试用例的过程，其实是适应度函数的优化过程。下面简单介绍使用遗传算法实现该方法的几个重要操作的具体操作： 1) 初始化测试用例集：为保证测试用例集的多样性，采用随机方法生成规模为M的初始测试用例集； 2) 编码形式：由于二进制编码易于表达、操作简单的优点，本方法采用二进制编码形式对原始个体进行编码； 3) 计算测试用例适应度：根据 f i t n e s s ( X ) 计算测试用例的适应度以指导测试集的进化； 4) 实施选择操作：有多种不同的选择策略，本方法采用轮盘选择法，将一个圆分为种群规模大小个扇形区间，区间大小为测试用例的相对适应度值。轮盘选择法保证了各用例被选中的概率与适应度值成正比，与本文适应度函数优化的思想相一致，根据测试用例的相对适应度，将父代的优良测试用例复制到子代； 5) 实施交叉操作：此操作的主要目的就是在解空间中搜索不同的可行解。本方法以固定的交叉概率 P c 为参照，在测试用例集中随机选择两个用例，对其实施动态概率的随机点交叉操作； 6) 实施变异操作：变异操作用于补偿基因丢失情况，保持个体多样性。本方法以固定的变异概率 P m 为参照，对用例实施动态概率的变异操作； 7) 终止条件：当迭代次数达到预定终止代数或用例适应度达到预定值时算法终止。