Regression testing minimization, selection and prioritization: a survey

摘要

有很多方法最大化积累下来的测试用例套件的价值:

  1. minimization
  2. selection
  3. prioritization

Minimization:消除冗余的测试用例以减少要跑的测试用例
Selection:识别与当前变更相关的测试用例
Prioritization:使缺陷尽早被检测到

1. 绪论

回归测试的目的是保证新引入的变更不会影响到代码已有的,未变更的部分的行为
一般来说最直接的方法是retest-all。但是重跑整个测试套件的开销是很大的

2. 背景

2.1 回归测试

SUT:System under test
保证SUT两个版本之间变更没有影响到已有的特性
符号约定:

符号含义
P \mathit{P} P当前版本的待测程序
P ′ \mathit{P'} P P \mathit{P} P的下一个版本
S \mathit{S} S当前版本的规范
S ′ \mathit{S'} S下一个版本的规范
T \mathit{T} T已有的测试套件
t \mathit{t} t测试套件中的测试用例
P ( t ) \mathit{P(t)} P(t) P \mathit{P} P在测试用例 t \mathit{t} t上的执行结果

2.2 不同类别技术间的区别

Definition 1 :Test Suite Minimization Problem
给定测试套件 T \mathit{T} T,测试需求 { r 1 , r 2 , … , r n } \{r_1,r_2,\dots,r_n\} {r1,r2,,rn} T \mathit{T} T的子集 T 1 , T 2 , … , T n \mathit{T_1},\mathit{T_2},\dots,\mathit{T_n} T1,T2,,Tn是满足测试需求 r i \mathit{r_i} ri的测试用例集合
问题:找到一个子集 T ′ \mathit{T'} T,满足所有的需求 r i \mathit{r_i} ri。子集 T i \mathit{T_i} Ti中的任一测试用例 t j t_j tj满足测试需求 r i \mathit{r_i} ri

测试用例选择技术减少测试套件的规模,大多数选择技术是修改敏感的(modification-aware)。

Definition 2: Test Case Selection Problem
给定程序 P \mathit{P} P,以及其修改版本 P ′ \mathit{P'} P和一个测试套件 T \mathit{T} T
问题:用于测试程序 P ′ \mathit{P'} P的测试套件 T ′ \mathit{T'} T

Definition 3:Test Case Prioritization Problem
给定测试套件 T \mathit{T} T,测试套件的排列集合 P T \mathit{PT} PT和一个映射 f : P T → R \mathit{f:PT\rightarrow}\mathbb{R} f:PTR
问题:找到 T ′ ∈ P T \mathit{T'}\in\mathit{PT} TPT,使得 ( ∀ T ′ ′ ) ( T ′ ′ ∈ P T ) ( T ′ ′ ≠ T ′ ) [ f ( T ′ ) ≥ f ( T ′ ′ ) ] (\forall\mathit{T''})(\mathit{T''}\in\mathit{PT})(\mathit{T''}\neq\mathit{T'})[\mathit{f(T')\geq f(T'')}] (T)(TPT)(T̸=T)[f(T)f(T)]

2.3 测试用例分类

回归测试可以分为两类:

  1. progressive regression testing
  2. corrective regression testing

两者的主要区别就是是否改动了specifications

然后将测试用例分为5类,头3类已经存在于当前的测试套件 T \mathit{T} T中:

  1. Reusable:这类测试用例执行两个版本间未改变部分的程序,这部分的测试用例在本次回归测试中是不需要被执行的。但是它们被称为reusable因为它们可能在之后的版本中重用

  2. Retestable:这类测试用例执行了 P ′ \mathit{P'} P在新版本中的修改部分,这类测试用例需要重跑

  3. Obsolete(过时的):这类测试用例可能是以下几种情况:

    1. 由于规范的修改,输入输出关联不再正确
    2. 由于程序修改,测试用例不再测试设计测试的部分
    3. 他们是结构相关的测试用例,但是不再对程序的结构覆盖有贡献

剩下的两种类型是在新版本 P ′ \mathit{P'} P中产生的:

  1. New-structural:对于修改程序的结构部分,提供修改部分的结构覆盖测试用例
  2. New-specification:修改了程序的规范后,新产生的测试修改部分规范的测试用例

3. 测试用例最小化

4. 测试用例选择

与测试用例最小化的区别是挑选出来的测试用例子集是受到当前版本变更的影响
对于测试用例 t \mathit{t} t,它是modification-revealing当且仅当 P ( t ) ≠ P ′ ( t ) \mathit{P(t)}\neq\mathit{P'(t)} P(t)̸=P(t)。给定下面两个假设,通过modification-revealing测试用例可以识别fault-revealing测试用例

  1. P-Correct-for-T Assumption:对于 t ∈ T \mathit{t\in T} tT P \mathit{P} P t \mathit{t} t上产生正确的输出
  2. Obsolete-Test-Identification Assumption:存在有效的流程来确定对于 t ∈ T \mathit{t\in T} tT,在 P ′ \mathit{P'} P是否过时

也就是说对于 t ∈ T \mathit{t\in T} tT,它在 P \mathit{P} P上产生正确的结果,那么它在 P ′ \mathit{P'} P上也期望产生相同的结果

测试用例是对于 P \mathit{P} P P ′ \mathit{P'} Pmodification-traversing的,当且仅当:

  1. 测试用例执行了 P ′ \mathit{P'} P中新的或者改动的代码
  2. 测试用例执行到了 P ′ \mathit{P'} P中之前执行过的代码

然后提出了第三个假设:

  1. Controlled-Regression-Testing Assumption

When P’ is tested with t, all factors that might influence the output of P’, except for the code in P’, are kept constant with respect to their states when P was tested with t.

不知道怎么翻译,直接搬过来了
懂了!就是控制变量法,除了新版本修改的代码,其他所有因素与原版本保持一致!

有了这些假设后,fault-revealing测试用例 T f r \mathit{T_{fr}} Tfrmodification-revealing测试用例 T m r \mathit{T_{mr}} Tmrmodification-traversing测试用例 T m t \mathit{T_{mt}} Tmt,和原始的测试套件 T \mathit{T} T有如下关系:

T f r = T m r ⊆ T m t ⊆ T \mathit{T_{fr}}=\mathit{T_{mr}}\subseteq\mathit{T_{mt}}\subseteq\mathit{T} Tfr=TmrTmtT

RTS算法是否safe主要基于A safe, efficient algorithm for regression test selection的概念:也就是选择算法要选择到所有可能发现 P \mathit{P} P P ′ \mathit{P'} P不一致行为的测试用例

很多方法、技术和标准用来进行RTS:

  1. 整数规划
  2. 数据流分析
  3. 符号执行
  4. 动态切片
  5. 控制流图 graph-walking
  6. 源代码文本差异
  7. SDG(系统依赖图)切片
  8. 路径分析
  9. 变更检测
  10. firewall
  11. 控制流图聚类识别
  12. design-based testing

4.1. 整数规划(IP)

把代码基本块作为单入口单出口的实体,实体内的语句顺序执行
比如有m个分割块,n个测试用例,选择测试用例向量记为 &lt; x 1 , x 2 , … , x n &gt; &lt;x_1, x_2, \dots, x_n&gt; <x1,x2,,xn>,那么RTS目标可以形式化地表示为:
m i n .   Z = c 1 x 1 + c 2 x 2 + ⋯ + c n x n s . t .   a 11 x 1 + a 12 x 2 + ⋯ + a 1 n x n ≥ b 1         a 21 x 1 + a 22 x 2 + ⋯ + a 2 n x n ≥ b 2         .         .         .            a m 1 x 1 + a m 2 x 2 + ⋯ + a m n x n ≥ b m min.\ Z=c_1x_1+c_2x_2+\dots+c_nx_n\\ s.t.\ a_{11}x_1+a_{12}x_2+\dots+a_{1n}x_n\geq b_1\\ \ \ \ \ \ \ \ a_{21}x_1+a_{22}x_2+\dots+a_{2n}x_n\geq b_2\\ \ \ \ \ \ \ \ .\\ \ \ \ \ \ \ \ .\\ \ \ \ \ \ \ \ .\\ \ \ \ \ \ \ \ \ \ \ a_{m1}x_1+a_{m2}x_2+\dots+a_{mn}x_n\geq b_m\\ min. Z=c1x1+c2x2++cnxns.t. a11x1+a12x2++a1nxnb1       a21x1+a22x2++a2nxnb2       .       .       .          am1x1+am2x2++amnxnbm

x i x_i xi表示对应第 i i i个测试用例是否选到,若选择则为1,否则为0
c i c_i ci表示执行测试用例的开销,那么优化目标 Z Z Z就是选择的测试用例子集的总开销时间
a i j a_{ij} aij为1时表示第 i i i个程序片段被测试用例 j j j执行了
b i b_i bi取决于对应的基本块是否被当前变更传递影响到

缺点:若控制流结构改变了,那么测试用例的依赖参数 a i j a_{ij} aij需要重新执行一遍测试套件进行更新

4.2 数据流分析方法

数据流分析识别 P ′ \mathit{P&#x27;} P中新的,修改的或者删除的definition-use对,选择执行这些对的测试用例

基于数据流分析的测试用例选择技术的缺点是它们不能检测到与数据流不相关的修改

比如,如果程序 P ′ \mathit{P&#x27;} P新增了一个过程调用,这个过程调用不接受任何参数,或者修改的语句不包含变量的使用,那么数据流技术不会选择出相关的测试用力

4.3 符号执行方法

在符号执行的程序中,所有的变量都被视为符号,而不是具体的值

Yau和Kishmoto的方法步骤大致如下:

  1. 静态分析代码和规范确定输入的partitions(分块?)
  2. 产生测试用例,使得每个partition都至少被执行一次
  3. 给定代码变更的信息,该技术识别受该变更的CFG上的边
  4. 记录测试用例在使用符号执行时经过的路径,选择所有能够到达修改代码部分的测试用例

在理论上,符号执行是很强大的,但是这个方法受限于符号执行的代数复杂度,这部分的开销会很大

4.4 基于动态切片的方法

该技术基于程序差异切片技术。

程序的执行切片是测试用例的一段执行轨迹,是被给定测试用例执行的一系列语句。

动态切片是与测试用例相关的在执行切片中对输出语句有影响的语句集

如图所示,在S3和S11处包含两个错误
QQ截图20190409144658.png
QQ截图20190409144900.png
为了让选择更精确,提出两个新的切片标准:相关切片近似相关切片。相关切片是相同测试用例和程序中的所有谓词语句的动态切片(其实没看懂,上原文)

A relevant slice of a program with respect to a test case is the dynamic slice with respect to the same test case together with all the predicate statements in the program that, if evaluated differently, could have caused the program to produce a different output.

举个例子,考虑图1中的S3。 T 4 T_4 T4的动态切片没有包含S3因为 T 4 T_4 T4class没有被S3与S8之间的语句影响。但是 T 4 T_4 T4的相关切片受S3影响因为它可能影响到输出

看图1-DS列,考虑测试用例 T 4 T_4 T4,对 T 4 T_4 T4进行动态切片不会包括S3,因为它没有执行到S3和S8之间的任何一个语句

再解释一下:动态切片只是执行切片轨迹中与输出相关的语句。对于 T 4 T_4 T4来说,它在执行过程中没有实行到S3与S8中间的语句,所以尽管S3与输出的变量class相关,但是在动态切片时也不会切出S3与S8中间的语句

还有其他例子懒得看了。。

Agrawal et al. 构建技术在变更不改变的CFG的待测程序上。只要CFG保持不变,那么CFG就是safe的,可以视为整数规划的一种改进。切片技术消除了整形规划的问题的形式化需求。然后Agrawal放宽了静态CFG的假设,以迎合SUT CFG中的修改。如果语句 s s s加到程序 P P P中,那么切片 s l sl sl包括了使用 s s s中定义变量的所有语句。相似地,如果一个谓词(啥是谓词,A logical expression which evaluates to TRUE or FALSE, normally to direct the execution path in code) p p p加入到程序 P P P中,那么切片 s l sl sl包含所有控制依赖于 p p p的语句。举个例子,如果增加的语句是一个简单输出语句,没有定义或使用任何变量,那么这个语句是modification-revealing。但是新的语句没有包含任何变量,它的增加不会影响已有切片,返回一个空的选择。

4.5 图遍历方法

Rothermel和Harrold提出基于控制流图、程序依赖图、系统依赖图和控制流图遍历的进行测试用例选择方法。控制依赖图和系统依赖图相似,但是缺少了数据依赖的信息。通过深度优先遍历P和P’,可以识别程序中的哪些点可以执行路径达到修改点。如果P的CDG中的节点与P’的CDG中的节点不等价,那么算法会选择执行不匹配节点的所有先驱的测试用例。基于CDG的选择技术不适合进行程序间的回归测试用例选择;他们推荐使用个体过程级别的技术。

之后他们扩展使用PDG进行程序内的选择,使用SDG进行程序间的选择。基于CDG的技术的一个弱点是由于缺少数据依赖,可能会选择到执行修改定义部分但是没有实际用到变量的测试用例。如果一个变量修改定义从来没使用过,那么它不会对任何输出产生影响,因此它可能包含了许多不必要的测试用例。PDG包含单个过程中的数据依赖,SDG扩展了整个程序到多个过程。

基于CFG的技术相比基于CDG,程序结构的表示更简单,所以一般来说也更有效率。但是CFG也缺少依赖信息,所以不能选出产生不同输出的测试用例。

图遍历算法也用来测试网络服务。

4.6 文本差异方法

识别SUT中变更的源代码文本。代码文本预处理成规范格式以消除差异。虽然这个技术在SUT的不同表示形式上操作,但是总体的技术流程和基于控制流的图遍历方法很相似

4.7 SDG(系统依赖图)切片方法

Bates和Horwitz提出基于程序依赖图(PDG)切片的测试用例选择方法。这个方法分两个阶段:

  1. 需要识别所有能被 P ′ P&#x27; P重用的测试用例。他们引入等价执行模式(equivalent execution pattern)的定义。如果语句s和s’分别属于P和P’,那么,s和s’是等价执行模式当且只当他们符合以下条件:

    1. 对于任何输入,P和P’都能正常终止,s和s’执行相同次数
    2. 对任何输入,P正常终止但P’没有,s’执行次数最多和s执行次数相同
    3. 对任何输入P’正常终止,但P没有,s执行次数最多和s’执行次数相同

使用程序切片,把语句分到不同的执行类。P中语句s和P’中语句s’属于同一执行类当且仅当任何测试执行s也执行s’

现在,语句P’中的语句s’受修改影响当且仅当下述其中一个条件成立:

  1. P中没有相关语句s
  2. s’的行为与s在P中的行为不等价

行为等价:如果s和s’在P和P’上的PDG切片是同构的,那么这些语句有等价的行为。对于每个受影响的语句P’,可重用的测试用例基于识别阶段的信息选择出来

该技术选择P’中修改的或新增的语句,它不选择从P中删除的语句的测试用例,所以这个方法是不安全的

4.8 路径分析

Benedusi构建从 P \mathit{P} P P ′ \mathit{P&#x27;} Pexemplar paths。比较这两个path,该技术把 P ′ \mathit{P&#x27;} Pexemplar paths分类为新建的,修改的,取消的和未修改的。 P \mathit{P} P执行的路径和所有测试用例是已知的;因此,选择所有可能会遍历到 P ′ \mathit{P&#x27;} P中修改的paths的测试用例

这个方法是not safe的,因为新建的和取消的paths也体现了 P \mathit{P} P P ′ \mathit{P&#x27;} P的变更,也有可能发现因变更而导致的bug

4.9 基于修改的技术

这个技术把 P \mathit{P} P和执行到它的测试用例对应上,然后抽取 P ′ \mathit{P&#x27;} P中的程序实体,识别其中从 P \mathit{P} P修改的实体,所有与 P \mathit{P} P修改实体相关的测试用例都应该被重测

这个技术可以视为图遍历方法的一个扩展变体,不同的是这个技术引入了程序实体这个概念,程序实体包括函数和非函数,比如变量、数据类型和宏指令等

这个技术的缺点在于指针处理,该技术要求所有的值创建和操作都从源代码中分析得到。这个技术使用时有一个假设:所有的指针计算都是well-bounded

4.10 防火墙技术

主要就是在系统需要重新测试的模块上画一道防火墙

这个技术把模块分成以下三类:

  1. No Change:模块A没有修改, N o C h ( A ) NoCh(A) NoCh(A)
  2. Only Code Change:模块A保持相同的规范但是代码修改了, C o d e C h ( A ) CodeCh(A) CodeCh(A)
  3. Spec Change:模块修改了规范, S p e c C h ( A ) SpecCh(A) SpecCh(A)

如果模块A调用了模块B,有9种A和B状态组合的方式。若 N o C h ( A ) ∧ N o C h ( B ) \mathit{NoCh(A)}\wedge\mathit{NoCh(B)} NoCh(A)NoCh(B),那么这个组合可以忽略,剩下8种组合方式

如果A和B都改变了代码或规范,那么A和B间的集成测试需要执行,当然,A和B的单元测试也需要重跑

最后还剩下4中组合方式,都是调用者或被调用者之间的一个没有修改。这些组合构成了集成测试的边界,也就是所谓的防火墙(firewall)

考虑模块为一个原子实体。如果一个模块被修改,所有测试了修改模块的集成的测试用例都应该被选择。因此,所有通过修改模块传递闭包覆盖到的测试用例都会选择到。

但是这个技术可能选择到能执行到修改模块的其他测试用例。

4.11 簇识别

这个技术分析待测程序的CFG。将有单一入口和单一出口的子图称为簇。给定程序 P \mathit{P} P及其修改版本 P ′ \mathit{P&#x27;} P

  • P \mathit{P} P中的每个簇包括了对于程序 P \mathit{P} P的修改
  • 有对应的 P ′ \mathit{P&#x27;} P中的簇与 P \mathit{P} P中的簇相关联
  • 把每个图中的簇用单个节点代替,图中的节点有一对一关系

在过程中,如果在修改的程序的CFG中找不到原始程序的CFG的节点的对应部分,那么该节点就标记为MOD,表示在这个节点上进行了修改。

和其他测试用例选择技术一样,这个技术需要记录每个测试用例的执行历史。一旦簇完整了,选择所有能够通过MOD簇的测试用例作为需要重跑的测试用例

这个技术的优点是他保证选择所有修改传递到的测试用例,无视修改的类型,如:增加删除语句或控制流结构

但是簇包含了SUT的很大一块区域,这个技术会多选很多测试用例(其中包含很多修改传递不到的测试用例),使用这个技术是为了保证回归测试时safe

4.12 基于设计的方法

面向基于UML设计提出一个黑盒,设计级别的RTS方法

假设设计和回归测试用例间能够跟踪,那么对UML设计模型的影响分析,可以在代码级别的测试用例上进行回归测试。技术的提出者实现了一个面向UML的自动影响分析工具,并且在学生项目和工业案例上进行了研究分析和评估

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值