代码覆盖率的务统计指标有哪些?如何合理设置?

接下来我们看一下代码覆盖率里面的指标,一开始我们就讲到了,代码覆盖率的含义就是哪些代码被跑到了,哪些代码没有被跑到,实际上没有那么简单,它分成了几个维度去考虑代码的覆盖情况,我们先来看第一个纬度,语句的覆盖。 


语句覆盖(StatementCoverage)又称行覆盖(LineCoverage),就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,不会包括头文件声明,代码注释,空行,等等,非常好理解。只统计能够执行的代码被执行了多少行。简单来说,就是这行代码只要被覆盖到了就是1,没有被覆盖到就是2。

代码测试

我们先来看上面这段代码,这里有价值的语句一共有3条语句:判断语句是一条,return 0是一条,return 1是一条。很多代码覆盖率会认定else不算,因为它就是一个关键字,实际上没有什么语句的价值。
如果每一行都执行到了,行覆盖率就是1,总共3行,3行都执行到了,行覆盖率就是100%。

 

稍微有点代码常识的人看到这里就能看出问题了,如果这个if语句我确实执行到了,但是它明显地有判断条件。


如果我第一个判断条件执行了,我就能判断出这个语句的真假,后面的判断条件不执行了,我就继续往下走。这个语句确实叫执行了,true false 都没有完全覆盖到而已,所以我们说行覆盖是最弱的代码覆盖。
语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。



除了行覆盖、语句覆盖之外,第二种覆盖叫做判定覆盖,后面我们有详细的例子,什么叫判定覆盖?


判定覆盖也叫分支覆盖(BranchCoverage),度量程序中每一个判定的分支是否都被测试到了。


这个很好理解,比如我们刚才的例子里有一个if语句,行覆盖就是一行行往下走,判定覆盖是指有分支的语句,每一个语句是否都被走到了。我们再来一起看一下这个例子。

代码测试

有的同学会说你的这个例子完整地有if有 else,所以说行一旦覆盖成功了,三句都走完了,那么你的分支覆盖肯定也是百分之百走完,也是成功的,因为我的if走了,else也走了。


我们试想一下,如果把下面的else盖住的话,没有这个else,只有if,如果你的语句覆盖里面的if走到了,return走到了,你的行覆盖率是百分之百,这个时候你并没有去测else分支,这个时候行覆盖率是100%,但是else的条件你并没有测到,这个时候只覆盖到了if为true的情况,没有覆盖到else分支,虽然else分支里面没有代码。


这个例子就说明判定覆盖和行覆盖还是有本质区别的。

条件覆盖(ConditionCoverage),它度量判定中的每个子表达式结果true和false是否被测试到了。为了说明判定覆盖和条件覆盖的区别,我们来举一个例子,假如我们的被测代码如下:


在刚才的例子里,如果if、else都走到了,那么你的分支覆盖肯定也是百分之百,但是条件覆盖不一定是百分之百。


什么意思呢,if整体为true,我确实走到了,if整体为false,也就是else,我确实也走到了,对于if判断语句来说,两个分支确实都走到了。


但这里面还有一个问题,if后面它是有两个判定条件的,咱们稍微有点代码常识的朋友都知道,不管什么语言,都有逻辑判断短路的问题。两个and判断,如果有一个and判断为false了,后面就不会判断了,所以说那个就不走了,不管走不走,你并没有覆盖到两个并列条件,两个子条件都为true或都为false的情况你并没有走到。


整体的判断语句你走到了,但是里面两个具体的分支判断条件分别的true、false你没有走到。这个时候你的分支覆盖率是百分之百了,但是你的条件覆盖率并不是百分之百。


路径覆盖(PathCoverage)它度量了是否函数的每一个分支都被执行了。有多个分支嵌套时,需要对多个分支进行排列组合。


因为现在只有一个if条件,所以不好看路径,我给大家举个例子,比如说两个判定条件,两个if,你只覆盖了第一个if判定条件的true和false以及第二个判定条件的true和false,但是两个并没有分别来走。
比如说第一个是true,第二个是false,或者第一个是false,第二个是true的这种交叉情况。也就是说没有把包含所有的if、else条件的整体当成一个完整的路径去处理,这个路径就有多种组合了。这就是第四个,叫路径覆盖。

所以说最粗略的覆盖是行覆盖,然后是判定覆盖,也叫分支覆盖,第三个是每个分支里面的小条件都被覆盖了叫条件覆盖,第四个是所有代码里面可能会出现的路径组合,判断分支的组合,叫做路径覆盖,由粗到细四个程度。


当然再往下划分还有一个圈复杂度,这个就不在咱们今天分享的范围内了。


下面我们再通过一个小例子去详细解说一下。

代码测试

上面是一个java的语句,一个foo函数,有a、b两个整型,有一个if条件,这个if条件里面有两个小的条件。接下来有一个else分支语句,最后有一个return语句。有一组判断,两个分支,三个语句(不算定义的话)。


TestCaes1: a=5,b=任意数字  


当a=5的时候,a<10这个条件成立,对于逻辑或来说,前面的条件为真,后面的条件就不用判断了,必然是为真的。

所以说我给出的第一组测试用例,当a=5,b=任意数字时,它都会走到分支一,我们再给一个值。


TestCaes2: a = 15,b =  15       

   
当a=15时,a<10不成立,进而去判断第二个条件,当b=15,b<10也不成立的时候,会走到else这里,这样也覆盖了分支二。

语句覆盖100%,分支覆盖也是100%,但是里面小条件的true和false并没有很完整地被覆盖。a<10为true、为false和b<10为true、为false的情况没有分别覆盖,因为逻辑短路的原因,所以你不能让它短路。
 
 完全的条件覆盖:


TestCase1: a = 5,b = 任意数字    ture X 

TestCase2: a = 15, b = 5            false, true 

TestCase2: a = 15, b = 15           false, false 


第一条,我先让a=5,b=任意数字,这个时候a<10这个条件为true的情况已经被覆盖。接下来通过a = 15, b = 5和a = 15, b = 15  这两组数据,让a<10这个条件为false时,b<10这个条件的true和false,都覆盖到了。


在这个逻辑或的条件中,每个分支的true和false都覆盖到了,这个时候才完成了我们所说的第3类覆盖,就是我们刚才所说的条件覆盖。对于这一个例子来说,上面所说的几种覆盖率就全部都覆盖到了。
下面我们再一起来看一个例子。

代码测试

对于这样两个并列的if条件来说,怎么来写语句测试用例以做到语句覆盖率100%、判定覆盖率100%、条件覆盖率100%、路径覆盖率100%。


TestCase a = 5,b = 5 ,nReturn = 11语句覆盖率100%


TestCase1 a = 5,b = 5,nReturn = 11

TestCase2 a = 15, b = 15, nReturn = 0

 

判定覆盖率100%,条件覆盖率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% 


从这里可以看出,如果我们想达到路径覆盖率100%的话,我们的测试用例一定是比前三种要多的。所以我们最终得出的结论是:路径覆盖率 > 判定(分支)覆盖 > 语句覆盖。


后面的内文章就进入到我们本系列文章的重点了,我们了解到了什么是覆盖率,也了解到了覆盖率的四种统计的维度,接下来的文章将带大家了解一下代码覆盖率工具以及实施方法。


相关推荐Java代码覆盖率工具Jacoco介绍       白盒测试——C/C++编程规范(22)