本文主要是介绍什么是代码覆盖度,引入代码覆盖度的好处,代码覆盖度的度量方法以及对应的测试用例设计方法
1. 什么是代码覆盖度
代码覆盖率分析实际上一种度量方式,间接度量质量的方法的过程,是在保证测试质量的时候潜在保证实际产品的质量,在程序中寻找没有被测试用例测试过的地方的流程,创建新的测试用例来增加覆盖率的流程。
代码覆盖分析是一种结构测试技术,属于白盒测试的范畴,结构化测试是以源代码的意图表现为依据来比较被测试程序行为的,与以需求规格为依据去比较被测程序行为的功能测试形成对比,结构化测试检查程序是如何工作的,以及代码结构和逻辑方面的潜在缺陷,而功能测试是不管程序内部是如何运作的,它只检查以及关心程序实现了什么。另外代码覆盖有时被称为“覆盖分析”、“测试覆盖分析”、“测试覆盖”、“覆盖监视器”等。
2. 代码覆盖的基本度量方法
代码覆盖度量方法有很多种,以下说明的是基本的度量方法
2.1语句覆盖(StatementCoverage 即SC)
这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,不包括像C++的头文件声明,代码注释,空行等。非常好理解,只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{} 也常常被统计进去。同时又称行覆盖(LineCoverage),段覆盖(SegmentCoverage),基本块覆盖(BasicBlockCoverage),基本块覆盖的基本单位是每一个非分支语句的序列。
优点:直接应用到被测对象代码里,不需要再处理代码
缺点:只覆盖代码中的执行语句,却不考虑各种分支的组合、对一些控制结构不敏感等。语句覆盖似乎能够比较全面的检验每一条语句,但是语句覆盖对程序逻辑的覆盖很低,常被人指责为“最弱的覆盖”。
例子:
Int foo ( int a, int b)
{
return a / b;
}
上诉代码测试人员编写如下测试案例:TeseCase: a = 10, b = 5
实际上本次测试的代码覆盖率达到了100%,并且所有测试案例都通过了。但是却没有发现最简单的Bug,比如,当我让b=0时,会抛出一个除零异常。另外语句覆盖并不报告循环是否达到了停止条件的情况,只报告循环体是否被执行过,在C、C++、Java中这种限制会影响到包含了Break语句的循环;Do-While循环无论如何都会执行至少一次,语句覆盖会把它看作与非分支语句同类,完全无视逻辑操作符,且不能够区别连续的Switch标签;
2.2判定覆盖(DecisionCoverage即DC)
它度量程序中每一个判定的分支是否都被测试到了。即设计足够的测试用例,使得程序中每个判定至少获得一次“真值”或“假值”,或者说使得程序中的每一个取“真”分支和“假”分支至少经历一次,同时又称分支覆盖(BranchCoverage),所有边界覆盖(All-EdgesCoverage),基本路径覆盖(BasicPathCoverage),判定路径覆盖(Decision-Decision-Path)。注意:整个布尔表达式被看成了一个单独的真假判定,不管它里面有没有“逻辑与&&”或者“逻辑非”操作符。
优点:简单且没有语句覆盖的那些问题,强于语句覆盖
缺点:由于布尔表达式里面的操作符,会忽略掉一些分支。
例子:
If(a&&(b||function()))
Statement1;
Else
Statement2;
测试用例:a=T,b=T时整个表达式就为真,当a=F时真个表达式就为假,这种情况下就把function()排除在外了。
2.3条件覆盖(ConditionCoverage即CC)
它度量判定中的每个子表达式结果true和false是否被测试到了。即构造测试用例使得每个判定语句中每个逻辑条件的可能值至少满足一次(即每一个被“逻辑与”或“逻辑非”分开的布尔表达式真假值情况)。
为了说明判定覆盖和条件覆盖的区别,假如被测代码如下(例子3):
Int foo(bool a,bool b,bool c)
{
Int x;
x=0;
if (a
&&(b||b)) // 判定
x=1;
return x;
}
设计判定覆盖案例时,只需要考虑判定结果为true和false两种情况,因此设计如下案例就能达到判定覆盖率100%:TestCaes1: a = T, b =T,c=T ;TestCaes2: a = F,b =F,c=F
设计条件覆盖案例时,需要考虑判定中的每个条件表达式结果,为了覆盖率达到100%设计如下的案例:TestCase3: a = F, b =T,c=T;TestCase4: a = T, b =F,c=T,可以看到在满足条件覆盖的时候把判定的两个分支也覆盖了。但是并不能说完全的条件覆盖可以保证完全的判定覆盖,例如我们取测试用例TestCase3: a = F, b =T,c=T;TestCase4: a = T, b =F,c=F。做到了条件覆盖但是无法做到完整的判定覆盖,注意:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false测试到了就OK了。
2.4条件判定组合覆盖(CDC)
是一种由条件覆盖和判定覆盖混在一起度量的方法,即设计用例使得判定中每个条件的所有可能(真/假)的值至少出现一次,并且每个判定本身的判定结果(真/假)也至少出现一次。
例如对于上诉例子设计用例:TestCaes1: a = T, b =T,c=T ;TestCaes2: a = F,b =F,c=F,达到了CDC的标准,但是例如判定的第一个运算符”&&”错写为“||”或者第二个运算符“||”错写为“&&”,使用设计的用例仍然能满足CDC要求,但是上诉错误的逻辑并未发现。
2.5路径覆盖(PathCoverage)
它度量了是否函数的每一个分支都被执行了。就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合,又称断言覆盖(PredicateCoverage)。
优点:需要进行比较彻底的测试
缺点:路径的个数为分支数目的指数倍。比如,如果一个有10个IF语句的函数,它就有1024条路径去测试,加了一条IF语句时,它的路径数就翻倍到了2048;由于数据间的关系,它有很多的路径是不可能被测试的。例如
if (success)
statement1;
statement2;
if (success)
statement3;
从路径测试的角度来看这段代码,它就有四条路径。但事实上,它只有两个是可行的:SUCCESS等于假和SUCCESS等于真。
2.6多条件覆盖(MCC)
所有布尔子表达式的组合全部覆盖,即设计用例使得每个判定中条件的各种组合都至少出现一次,满足多条件覆盖的测试用例也能满足判定覆盖、条件覆盖和条件/判定组合覆盖。当程序中的判定语句较多时,条件取值的组合数目较多,每增加一个逻辑操作符,测试用例所需要的数量就要增加一倍,另外确定最小测试用例集的过程非常冗长并且对于相似复杂度的条件所需要的测试用例数相差可能非常大。
2.7其它度量方法
修正条件判定覆盖MCDC,它要求每一个程序模块的入口和出口都要考虑至少要被调用一次,每个程序的判定到所有可能的结果至少转换一次,其次,程序的判定被分解为通过逻辑操作符(and、or)连接的bool条件,每个条件对于判定的结果值是独立的。
功能覆盖,报告是否调用了每一个函数或者过程,在初步测试时可以保证所有功能都得到一些覆盖,可以快速找出一些不足之处。
LCSAJ覆盖,路径覆盖的变种,它考虑的那些容易在程序代码里表现出来及不需要流图的子路径,一个LCSAJ是指一序列的源代码按顺序执行,这种覆盖方式比判定覆盖更加彻底,但是不能避免那些不可行的路径。
数据流覆盖,这种路径覆盖的变种只考虑从分配的变量到后续参考的变量之间的子路径的情况。它的优点就是它所考虑到的路径都是和程序处理数据的方法直接相关。它第一个缺点是它并不包含判定覆盖。另外一个缺点就是复杂。
RACE覆盖,这种度量报告了是否多线程在同一时间执行了同样的代码。它可以帮助查到同时对资源存取这样的问题。它对于多线程程序的测试是非常有用的,比如说在一个操作系统里使用。
关系操作符覆盖,这种度量报告的是具有关系操作符(<,<=,>,>=)的时候,边界值的情况。 它假想的是这些边界测试用例查到一些差一(OFF-BY-ONE)错误,以及用了错误的关系操作符(比如,用<代替了正确的<=) 。
表覆盖,这种度量讲的是在某一数组中的每一个元素是否被引用了。这种方法对于被有限状态机控制的程序非常有用。
3. 如何给出代码覆盖度指标
测试过程中代码覆盖率常常被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况,那代码覆盖率应该达到80%、90%还是100%呢。
判定覆盖包括了语句覆盖,原因是当执行过每一条分支的时候,肯定会导致每一条语句都被执行了,条件/判定覆盖包括了判定覆盖与条件覆盖(这是由它们的定义得出来的),路径覆盖包括了判定覆盖,断言覆盖包括了路径覆盖和多条件覆盖,以及其它大多数度量方法。
每一个项目都必须要根据可用的测试资源以及防止推迟发布的重要性,来选择一个可以作为发布标准的覆盖率最小值。很明显的,和安全相关的软件,它的覆盖率就要有一个高一些的值。还有,你也可以把单元测试的覆盖率最小通过值设置得比系统测试的要高。它这样做的原因是低层次的代码错误可以影响到很多高层的调用代码。
当你使用语句覆盖,判定覆盖,或者条件/判定覆盖时,覆盖率的最小通过值就可以设为80%~90%,甚至更高。选择一个中间的覆盖率目标可以很有效的提高测试生产率,过高会导致花费较多的时间和精力在追求覆盖度上,不如在类似于评审的测试活动上发现更多bugs。覆盖率目标顺序为:源代码或者类的90%都可以调用至少一个函数;调用至少90%的函数;每个函数至少获得90%的条件/判定覆盖率;获得100%的条件/判定覆盖率。
4. 参考资料
1.coderzh的文章“http://www.cnblogs.com/coderzh/archive/2009/03/29/1424344.html”
2.书籍“软件评测师教程”