代码覆盖率是用例衡量代码被覆盖程度的一种度量方式。它最初是白盒测试的一个指标,后来被广泛应用于系统测试领域
代码覆盖率的度量方式有很多种,这里介绍常用的几种
- 语句覆盖
语句覆盖又叫行覆盖,是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了,让我们看一段代码
int foo(int a,int b)
{
return a/b;
}
如果我们设计了这样一组用例
TC :a=1,b=3
很明显,语句覆盖率达到了100%。但是,聪明的你一定想到了,语句覆盖率虽然达到了100%,却没有发现最简单的bug∶ b=0时,会抛出一个除零异常。好吧,看来这个语句覆盖不是很靠谱。语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等。
- 判定覆盖
判定覆盖(Decision Coverage)度量程序中每一个判定的分支是否都被测试到了。废话不说,直接上代码:
int foo(int a,int b){
if (a<10||b<10)//判定
{
return 0; //分支一
}
else
{
return 1;//分支二
}
}
设计判定覆盖案例时,我们只需要考虑判定结果为true和false两种情况,因此,设计如下的案例就能达到判定覆盖率100%:
TestCaes1: a=5, b =任意数字 覆盖了分支一
TestCaes2: a=5, b =15 覆盖了分支二
3.条件覆盖
条件覆盖(Condition Coverage)度量判定中的每个子表达式结果true和false是否被测试到了,例如:
int foo(int a,int b)
{
if(a<10 || b<10)
{
return 0;
}
else
{
return 1;
}
}
设计条件覆盖案例时,我们需要考虑判定中的每个条件表达式结果,为了覆盖率达到100%,设计了如下的案例:
TestCase1: a=5, b =5 true, true
TestCase4: a=15, b=15 false,false
通过上面的例子,我们应该很清楚判定覆盖和条件覆盖的区别。需要特别注意的是:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false都测试到了就行了。因此,我们可以这样推论:完全的条件覆盖并不能保证完全的判定覆盖。比如上面的例子,假如设计的案例为:
TestCase1: a=5, b=15 true,false 分支一
TestCase2: a=15, b=15 false ,true 分支二
我们看到,虽然我们完整地做到了条件覆盖,但是却没有做到完整的判定覆盖,只覆盖了分支一。从上面的例子也可以看出,这两种覆盖方式看起来似乎都不如听上去那么完美。我们接下来看看第四种覆盖方式。
4.路径覆盖
路径覆盖(Path Coverage)度量函数的每一个分支是否都被执行到。这句话也非常好理解,就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合,可想而知,测试路径会随着分支的数量指数级别地增加。比如下面的测试代码中有两个判定分支:
int fo foo(int a, int b)
{
int nReturn =0;
if (a<10)
{
nReturn +=1;
}
if(b<10)
{
nReturn +=10;
}
return nReturn;
}
被测代码中nReturn的结果一共有四种可能的返回值:0,1,10,11,而上面针对每种覆盖率设计的测试案例只覆盖了部分返回值,因此,可以说使用上面任一种覆盖方式,虽然覆盖率达到了100%,但是并没有测试完全。接下来我们看看针对路径覆盖设计出来的测试案例:
TestCase1 a=5, b=5 nReturn =0
TestCase2 a=15, b=5 nReturn =1
TestCase3 a=5, b=15 nReturn =10
TestCase4 a=15, b=15 nReturn =11
路径覆盖率100%。太棒了!路径覆盖将所有可能的返回值都测试到了。这也正是它被很多人认为是“最强覆盖”的原因。