Skip to main content

第11章 变异测试

第11章 变异测试

到了这个阶段课程有很多一些专题测试,专题测试的话都是解决专题的问题。这节课讲的内容的话就是说是这个叫做变异测试,就是相当于是这种生物的变异。变异测试本身的话,它是一个非常特殊的一个测试的方法。

一、变异测试

1)测试概述

变异测试是在解决测试充分性的问题。怎么样的测试才叫充分?我们可以用测试的覆盖率来评估。黑盒的也好,白盒的也好,每一种都可以通过测试覆盖率评估。变异测试的话,它也从另外一个角度去看了一下测试的充分性。变异测试可以加强测试的充分性

变异测试它这个技术出来以后,它解决的问题说我要加强测试的充分性,它不是真正去解决某一个充分性的问题。

满足覆盖率了以后这个测试就充分吗?

  • 如果说脱离覆盖率指标基础的话,你这个充分性从宏观意义上来讲的话,很难去保证这个充分性。
  • 怎么去理解这个测试的充分性?

2)充分性

  • 我们有一个程序 $P$。我们里面有 $n$ 个需求,$r_1$ 到 $r_n$ 这些需求。我们的程序是要满足这些需求而设计实现的
  • 测试集合为 $T$,包括 $k$ 个测试用例。做完测试以后,你会有个用例的这个用例库。
  • 问题就是测试集合是我们自己设计的。我们原来的测试方法,是在覆盖率的基础上去做的测试的充分性,脱离了那个覆盖率,你是无法去回答整个一个程序的测试充分性的问题。
  • 所以我们原来的测试方法,都不能解决回答这个问题。测试方法都是在效率和这个测试的效果之间做平衡的
  • 所以我们要增强测试的充分性。即使给了一个测试集,他执行出来是正确的。但是我们也不能说它是充分的。所以我们就有了变异测试。

3)变异测试和结果

  • 变异测试就是:把我原来的程序P,修改为P1,我对这个修改后的程序针对原来的测试用例集再做去做测试,一般来说原来可以通过的测试集合现在不能通过(当然可能也能通过)

  • 思考:如果改了程序,某个测试用例还能通过,这说明这个测试用例设计的不好,哪怕程序有问题也检测不到(从这个角度也能理解不充分)

  • 当我们对于程序做变异处理的时候,其实有两种结果:

    • 第一个你可能改一些语义上不等价的
    • 第二个,改完之后两个语义是一样的
  • 如果任何的测试用例都不能区分P和P1(修改后的变异体),这说明修改没有什么区别,没有产生什么影响。对于这种等价的变异体,我们一般要去除【不能要等价变异体】

4)变异测试步骤

  • 变异测试的步骤:

    • 首先会拿到一个程序P和相关的测试用例集,我们需要生成很多的变异体P1、P2、Pk等(一共k个)
    • 然后用变异体去跑测试用例集合,看看那些变异体跑出来和原来一模一样,那些可能是等价变异体,把等价变异体的数量记作 $e$
    • 另外的非等价的变异体如果发现有测试用例能通过,那说明原来的测试用例集合可能不太充分。我们把这种函数的数量记作 $k1$
    • 如果 $K=K1$ 那就说明,测试集合 $T$ 是有效充分的
    • 如果不是,那就要计算 $MS = k_1/(k-e)$
  • 变异测试的核心是区分等价变异体。

二、举例和总结

1)变异测试

  • 假设有下面的一个函数,正确的应该是返回x+y
  • 但是我在测试的时候,测试用例里面y都是0。所以就没有发现
int foo(int x, int y){
return (x-y);
}
// 测试用例 x=1,y=0;
// 测试用例 x=-1,y=0
  • 通过变异测试,首先修改原来的程序,模拟程序员犯的错误
// M1
int foo(int x, int y){
return (x+y);
}
// M2
int foo(int x, int y){
return (x-0);
}
// M3
int foo(int x, int y){
return (0+y);
}
  • 然后填写下表,一旦发现有一个测试用例可以区分,和foo算出来的不一样,那就要killed掉这个变异体!
Testfoo(t)M1(t)M2(t)M3(t)
t1(x=1,y=0)1110
t2(x=-1,y=0)-1-1-10
LiveLiveKilled
  • 发生三个里面Killed了一个,就是说明测试用例不充分。所以我们要增加测试用例。比如这个例子里面,就要增加y不是0的时候的测试用例。
  • 注意:如果发现了多个变异体Live,我们要增加用尽可能少的测试用例,来区分变异体和原来的(达到Killed他的目的)越少越好,并不是要每个都单独设计

2)变异体特点

变异体的特点:

  • 可达性:测试用例 $t$ 执行时需要覆盖到变异语句 $s$ 。 因为变异体 $m$ 内其他语句与 $P$ 相同,如果测试用例 $t$ 不能执行 $m$ 中的 $s$ 语句,则 $t$ 在 $P$ 和 $m$ 上的运行结果必然一致,即 $t$ 不能检测到变 异体 $m$ 。
  • 传染性:测试用例 $t$ 在执行完 $P$ 和 $m$ 的语句 $s$ 后程序 状态不一致。
  • 传播性:执行完语句 $s$ 后的不一致的程序状态将导致 程序 $P$ 和 $m$ 的输出不一致。

特别要注意的是等价变异体,因为程序生成变异体的时候,可能生成各种:

  • 下面的两个就是等价,变异体和原来的没有区别
for (int i =0; i < 5; i++){
sum += a[i]
}

for (int i =0; i != 5; i++){
sum += a[i]
}

  • 一般在工程里面,会有5%的等价变异体出现。

3)自动化生成变异体

  • 一般自动化生成变异体的时候有下面的类型:
  • 变量替换:z=a+b换为 z=a+a
  • if条件翻转:if(x<y)换成 if(x<=y)或者 if(x>y)
  • 数值加减一:z=a+b换为 z=a+b-1
  • 变量替换为0:z=a+b换为 z=a+0
  • 加减操作翻转:z=a+b换为 z=a-b

4)高阶变异体

  • 变异的时候可以只修改一个地方,就是一阶变异体,多处修改就是高阶变异体
  • 一般来说一阶变异体就足够测试了,模拟程序员犯的简单错误
  • 考试的时候不要担心,只要按照要求做,如果生成的变异体不能说明不充分,也没有关系

5)变异测试工具

  • 变异测试工具的特点:
  • 第一的话里面有可选择变异体的操作符
  • 然后有测试集合
  • 有自动化执行的工具,评估结果,比对变异体和原来的
  • 不能完全准确的判断是不是等价变异体,只能通过大概来判断是不是等价变异体