第二章 测试用例的设计
软件测试中最重要的因素是设计和生成有效的测试用例,测试设计如此重要,原因在于测试是不可能完全测试的,最优的策略是尽可能完全的测试。由于时间和成本的约束,软件测试的关键问题是:在所有可能的测试用例中,哪个子集最有可能发现最多的错误?
如何设计出一个严格的测试设计,尽可能多的发现问题 ?
建议 :将白盒测试和黑盒测试组合使用,一般先使用黑盒测试方式设计测试用例,然后通过分析程序内部逻辑,用白盒测试方法来设计补充的测试用例。
2.1 白盒测试
白盒测试关注的是测试用例执行的程度或是覆盖程序逻辑结构的程度。完全的白盒测试是将程序中的每条路径都执行到,白盒测试实际上逻辑覆盖测试,分为以下几个覆盖要求:
- 语句覆盖
- 判定覆盖
- 条件覆盖
- 判定/条件覆盖
- 多重条件覆盖
测试需求或者业务逻辑 :
正确的实现代码,实际上开发的代码可能不是这样实现的,白盒测试不一定是对代码测试,而是对测试程序的内部逻辑。
public int foo(int a,int b,int x) {
if (a > 1 && b == 0) {
x = x/a;
}
if (a == 2 || x > 1) {
x = x+1;
}
return x;
}
2.1.1 语句覆盖
语句覆盖要求:每条语句至少执行一次;
语句覆盖是最起码的测试要求,要求设计足够多的测试用例,使得每一条语句至少被执行一次,对逻辑的覆盖没有要求,不能检查出代码的逻辑错误,所以为了更充分的测试,需要采用后面的介绍的其他逻辑覆盖方法。
根据需求 ,设计测试用例走过ABCDE路径, a=2,b=0,x=任何值,满足每条语句至少被执行一次;
虽然满足语句覆盖,但是程序实现有可能写成如下两种情况第一个&&错误写成||,第二个x>1错误写成x<1 ; 所以语句覆盖,有可能漏测试,没什么大的实际用处,通常使用更严格的逻辑覆盖准侧 :判定覆盖或分支覆盖
public int foo(int a,int b,int x) {
if (a > 1 || b == 0) {
x = x/a;
}
if (a == 2 || x < 1) {
x = x+1;
}
return x;
}
2.1.2 判定覆盖
判定覆盖又叫分支覆盖,该准则要求必须编写足够的测试用例,使得每一个判断都至少有一个为真和为假的输出结果,换句话说就是每条分支路径都必须至少遍历一次。判定覆盖一定可以满足语句覆盖。但是仍然有二种例外情况:
- 程序中不存在判断
- 程序的方法有多重入口,只有从特定的入口进入时,某条特定的语句才会执行
测试路径分析
ace : 两个判断都是True
abd : 两个都是False
acd : 第一个True,第二个False
abe : 第一个False,第二个True
选择ace和abd 或 acd和abe 都可以满足,但是通常选acd和abe ,满足判定覆盖的要求,设计输入 a=3,b= 0,x =3 和 a=2,b=1 , x=1,
虽然满足了判定覆盖,每一个分支的true和false都被执行到了,但是第二个判断有两个子条件是或关系,其中一个为真,第二个判断就会被忽略,如果实现的代码写错了,如下 :把X>1写成x<1 , 用例也是可以通过,分支判断也满足,虽有有逻辑漏测试的情况。
public int foo(int a,int b,int x) {
if (a > 1 && b == 0) {
x = x/a;
}
if (a == 2 || x < 1) {
x = x+1;
}
return x;
}
2.1.3 条件覆盖
条件覆盖:该准则的要求是编写足够的测试用例以确保判断中的每个条件的所有的可能结果至少执行一次,程序的每个入口都被执行一次,每一个判断的子条件都有真和假的结果被测试用例覆盖到。
业务逻辑的条件:a>1 , b=0, a =2, x>1 , 因此要设计测试用例,使得这四个测试条件都出现为真和假;在第一个判断中,有a>1,a<=1,b=0,b != 0 , 在第二个判断中,有a=2,a != 2 , x>1 ,x <=1,所以最终组合选择
a>1 且 !=2,和 a > 1 且 = 2,和a<= 1, 所以 a选择3, 2 , 1 ; b的选择就是1 和 0,x的取值是 0 和 2
用例设计 :
a = 3,b = 1,x=2 路径abe
a= 2,b = 0,x=0 路径ace
a = 1,b = 1 ,x=0 路径abd
2.1.4 判定/条件覆盖
条件覆盖可能存在的问题:有可能设计的条件覆盖是满足的,但是某些判断的结果是组合条件,组合结果永远是False或者True,就会有问题,所以判定覆盖和条件覆盖要同时满足
判定/条件覆盖:该准则要求设计出充足的测试用例,将一个判断中的每个条件的所有可能的结果至少执行一次,将每个判断的所有可能的结果至少执行一次,将每个入口都至少调用一次。
2.1.5 多重条件覆盖
判定条件覆盖的缺点:虽然看上去所有的条件的可能结果都被执行了,但是由于某些条件会屏蔽掉其他的条件,常常并不能全部执行;
其中的原因是 "与"和 "或" 表达式中某些条件的结果可能会屏蔽掉其他条件的判断,如果 与 表达式中有一个是假,那么无须计算该表达式中的后续条件,如果或表达式中,有一个为真,那么无须计算后续条件,因此条件覆盖或判定/条件覆盖则不一定发现逻辑中的错误。多种条件覆盖准则能够部分解决这个问题。该准则要求编写足够多的测试用例,将每个判定中所有可能的条件结果的组合,以及所有入口都执行一次。
上面测试用例条件的组合必须满足一下8种组合:
1. a>1, b=0 5. a= 2, x >1 真
2. a<=1, b=0 6. a= 2, x <= 1 真
3. a>1 , b !=0 假 7. a != 2 , x > 1 真
4. a<=1 b != 0 假 8 a != 2 , x <= 1
设计测试用例四个满足了所有的逻辑覆盖:
a=1 b=0 , x=1 路径ABD
a=1 b=1 , x=2 路径ABE
a=2 b=0 ,x=2 路径ACE
a=2 b=1 , x=1 路径ABE
但是从路径的分析来看,遗漏ACD路径,所以应该增加ACD路径的测试用例,才能完成覆盖逻辑。
白盒测试的准则 :
每个判断只包含一种条件,最简单的测试准则是 将每个判断的所有结果都至少执行一次,
判断包含多重条件, 最简单的测试准则是设计足够数量的测试用例,将每个判断的所有可能结果的条件组合都至少执行一次。以及所有的程序入口都执行一次。
总结一下:
在实际的操作中,要从代码分析和代码调研入手,可以选择上述方法中的某一种,或者好几种方法的结合,设计出高效的测试用例,尽可能全面地覆盖到代码中的每一个逻辑路径。