代码覆盖率浅谈

代码覆盖率浅谈

在做单元测试时,代码覆盖率常常被拿来作为衡量测试好坏的指标,甚至,用代码覆盖率来考核测试任务完成情况,比如,代码覆盖率必须达到80%或 90%。于是乎,测试人员费尽心思设计案例覆盖代码。用代码覆盖率来衡量,有利也有有弊。本文我们就代码覆盖率展开讨论,也欢迎同学们踊跃评论。

首先,让我们先来了解一下所谓的“代码覆盖率”。我找来了所谓的定义:

代码覆盖率 = 代码的覆盖程度,一种度量方式。

上面简短精悍的文字非常准确的描述了代码覆盖率的含义。而代码覆盖程度的度量方式是有很多种的,这里介绍一下最常用的几种:

1. 语句覆盖(StatementCoverage)

又称行覆盖(LineCoverage),段覆盖(SegmentCoverage),基本块覆盖(BasicBlockCoverage),这是最常用也是最常见的一种覆盖方式,就是度量被测代码中每个可执行语句是否被执行到了。这里说的是“可执行语句”,因此就不会包括像C++的头文件声明,代码注释,空行,等等。非常好理解,只统计能够执行的代码被执行了多少行。需要注意的是,单独一行的花括号{} 也常常被统计进去。语句覆盖常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等等。假如你的上司只要求你达到语句覆盖,那么你可以省下很多功夫,但是,换来的确实测试效果的不明显,很难更多地发现代码中的问题。

这里举一个不能再简单的例子,我们看下面的被测试代码:

int  foo( int  a,  int  b)
{
   
return   a  /  b;
}


假如我们的测试人员编写如下测试案例:

TeseCase: a  =   10 , b  =   5


测试人员的测试结果会告诉你,他的代码覆盖率达到了100%,并且所有测试案例都通过了。然而遗憾的是,我们的语句覆盖率达到了所谓的100%,但是却没有发现最简单的Bug,比如,当我让b=0时,会抛出一个除零异常。

正因如此,假如上面只要求测试人员语句覆盖率达到多少的话,测试人员只要钻钻空子,专门针对如何覆盖代码行编写测试案例,就很容易达到主管的要求。当然了,这同时说明了几个问题:

    1.主管只使用语句覆盖率来考核测试人员本身就有问题。

    2.测试人员的目的是为了测好代码,钻如此的空子是缺乏职业道德的。 

    3.是否应该采用更好的考核方式来考核测试人员的工作? 

为了寻求更好的考核标准,我们必须先了解完代码覆盖率到底还有哪些,如果你的主管只知道语句覆盖,行覆盖,那么你应该主动向他介绍还有更多的覆盖方式。比如:

2. 判定覆盖(DecisionCoverage)

又称分支覆盖(BranchCoverage),所有边界覆盖(All-EdgesCoverage),基本路径覆盖(BasicPathCoverage),判定路径覆盖(Decision-Decision-Path)。它度量程序中每一个判定的分支是否都被测试到。这句话是需要进一步理解的,应该非常容易和下面说到的条件覆盖混淆。因此我们直接介绍第三种覆盖方式,然后和判定覆盖一起来对比,就明白两者是怎么回事了。

3. 条件覆盖(ConditionCoverage)

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

复制代码
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 
=   15 , b  =   15          覆盖了分支二

 
设计条件覆盖案例时,我们需要考虑判定中的每个条件表达式结果,为了覆盖率达到100%,我们设计了如下的案例:

TestCase1: a  =   5 , b  =   5         true,  true
TestCase4: a  =   15 , b  =   15     false, false


通过上面的例子,我们应该很清楚了判定覆盖和条件覆盖的区别。需要特别注意的是:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false测试到了就OK了。因此,我们可以这样推论:完全的条件覆盖并不能保证完全的判定覆盖。比如上面的例子,假如我设计的案例为:

TestCase1: a  =   5 , b  =   15    true,  false   分支一
TestCase1: a 
=   15 , b  =   5    false, true    分支一

 
我们看到,虽然我们完整的做到了条件覆盖,但是我们却没有做到完整的判定覆盖,我们只覆盖了分支一。上面的例子也可以看出,这两种覆盖方式看起来似乎都不咋滴。我们接下来看看第四种覆盖方式。

4. 路径覆盖(PathCoverage)

又称断言覆盖(PredicateCoverage)。它度量了是否函数的每一个分支都被执行了。 这句话也非常好理解,就是所有可能的分支都执行一遍,有多个分支嵌套时,需要对多个分支进行排列组合,可想而知,测试路径随着分支的数量指数级别增加。比如下面的测试代码中有两个判定分支:

复制代码
int  foo( int  a,  int  b)
{
    
int  nReturn  =   0 ;
    
if  (a  <   10 )
    {
//  分支一
        nReturn  += 1 ;
    }
    
if  (b  <   10 )
    {
//  分支二
        nReturn  += 10 ;
    }
    
return  nReturn;
}
复制代码


对上面的代码,我们分别针对我们前三种覆盖方式来设计测试案例:

a. 语句覆盖

TestCase a = 5, b = 5   nReturn = 11

 语句覆盖率100%


b. 判定覆盖

TestCase1 a = 5,   b = 5     nReturn = 11

TestCase2 a = 15, b = 15   nReturn = 0

判定覆盖率100% 


c. 条件覆盖

TestCase1 a = 5,   b = 15   nReturn = 1

TestCase2 a = 15, b = 5     nReturn = 10

条件覆盖率100% 

 

我们看到,上面三种覆盖率结果看起来都很酷!都达到了100%!主管可能会非常的开心,但是,让我们再去仔细的看看,上面被测代码中,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% 

复制代码


太棒了!路径覆盖将所有可能的返回值都测试到了。这也正是它被很多人认为是“最强的覆盖”的原因了。

还有一些其他的覆盖方式,如:循环覆盖(LoopCoverage),它度量是否对循环体执行了零次,一次和多余一次循环。剩下一些其他覆盖方式就不介绍了。

总结

通过上面的学习,我们再回头想想,覆盖率数据到底有多大意义。我总结了如下几个观点,欢迎大家讨论:

a. 覆盖率数据只能代表你测试过哪些代码,不能代表你是否测试好这些代码。(比如上面第一个除零Bug)

b. 不要过于相信覆盖率数据。

c. 不要只拿语句覆盖率(行覆盖率)来考核你的测试人员。

d. 路径覆盖率 > 判定覆盖 > 语句覆盖

e. 测试人员不能盲目追求代码覆盖率,而应该想办法设计更多更好的案例,哪怕多设计出来的案例对覆盖率一点影响也没有。

作者:CoderZhCoderZh的技术博客 - 博客园
微博:http://t.sina.com.cn/coderzh 
出处:http://coderzh.cnblogs.com
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:  单元测试C/C++软件测试
3
0
(请您对文章做出评价)
« 上一篇: 代码覆盖率工具大全
» 下一篇: CCNET+MSBuild+SVN实时构建的优化总结
posted @  2009-03-29 14:45  CoderZh 阅读( 17971) 评论( 32编辑  收藏
  
#1楼   2009-03-29 15:18  Eri[未注册用户]
太复杂,只会用VS的代码分析。
它说是多少就多少。
  
#2楼   2009-03-29 16:52  我开始做减法   
你的文章很精彩!
在我们小组的测试中,将测试数据的设计放在测试的第一位,今天看见你的文章,使我产生了共鸣的感觉。
不知道你能否在测试数据的构造上分享一下你的经验。目前,我们小组拟设计一个框架专门用于各种测试数据的维护,不知道你对此有何看法。
希望能够得到你的回复,谢谢。

  
#3楼   2009-03-29 17:29  徐少侠   
构造测试数据

边界值分析法,因果图分析等等都能用得上啊
  
#4楼   2009-03-29 17:44  Nick Wang   
测试覆盖率于产品质量没有必然联系,或者说没有任何的联系。它完全反应不了程序的质量。

但是它能反应你在测试上花费的注意力和努力,它能反应那些代码缺少测试。测试覆盖率高是好事,覆盖率低就要问一问自己为什么了。虽然不能直接表现质量,但是可以间接作为质量的参考,或者是警报。毕竟衡量质量的方法不止一种,不能只依赖其中的某一种,而是要相互结合
  
#5楼   2009-03-29 20:25  jolboy   
我觉得只能体现出代码中没有废代码!或者说代码精炼,至于错误,覆盖率是检查不出来的! 
我以前做过这类测试项目,60个人干了一个月~不仅要编写测试代码测试覆盖率,如果发现错误还得修正错误~要不是客户要求要这个东西,一般都不去搞的~~累死人~
  
#6楼   2009-03-29 20:27  hyddd   
文章很好,值得学习~

我也以前也做了一下代码覆盖率,不过没总结,惭愧一下,我的感觉是代码覆盖率只是一种辅助的手段,它的作用是告诉测试人员还有哪些代码你没有考虑到,最重要还是你对测试案例的设计。
我做模块接口的代码覆盖率时,开始的时候并没有直接看代码,而是根据几口的功能和参数设计测试案例,然后再做覆盖率,看有什么地方没有测到,考虑是否要追加测试案例。
最后,我的想法是代码覆盖率还是很重要的,我这样说是因为有两点:1.程序的风险很可能就存在于代码覆盖率没有涉及的地方。2.汇报工作时,我们需要以量化的方式给别人看,现在的老大们整天以代码覆盖率去考核测试人员,就是因为以上原因,但注意,他这样做是建立在对你信任的基础上的,就是你说的职业道德,对于想蒙混过关的人,我只能说一句:出来混,迟早要还~~~~
我们组培训的时候讲过 代码覆盖率可以帮你改进测试 但是没法告诉你测试质量如何 
路径覆盖100%只是理论上存在 带循环和多线程的实际环境中 只能覆盖极小部分路径
  
#8楼 [ 楼主2009-03-29 22:01  CoderZh   
@我开始做减法
谢谢你的回复
可以看出,你们小组做的非常不错!说实话,我在“测试数据的构造上”经验不多,你能否介绍一下你们专门用于各种测试数据的维护的框架呢?
  
#9楼 [ 楼主2009-03-29 22:03  CoderZh   
@Nick Wang
恩。说的非常好!
  
#10楼 [ 楼主2009-03-29 22:12  CoderZh   
@jolboy
正如其他人回复所说的,代码覆盖率也不是一无是处。
从你的经历中可以看出,当代码覆盖率被当做考核的重要标准时,它的意义也丧失了许多。
  
#11楼 [ 楼主2009-03-29 22:19  CoderZh   
@hyddd
你说的很对。
不过我觉得完全可以换一种考核标准,如果只拿代码覆盖率,很容易走极端。
  
#12楼 [ 楼主2009-03-29 22:23  CoderZh   
@winter-cn,我也不能总是不登录是吧
没错。(你的名字很有个性。。。)
  
#13楼 [ 楼主2009-03-29 22:24  CoderZh   
@徐少侠
看的出你很有经验。
  
#14楼   2009-03-29 22:30  hyddd   
@CoderZh
关键有些东西不好量化~~~代码覆盖率应该建立在良好的案例s的基础上,否则又回到的了一个关于测试人员水平的基础问题:测试案例s设计是否良好~~~~你是不是有什么想法啊?
  
#15楼 [ 楼主2009-03-29 23:21  CoderZh   
@hyddd
正如“我开始做减法"所说,他们将”测试数据的设计放在测试的第一位“是很有道理的。我觉得对案例设计的质量,能否发现高质量的BUG方面进行考核效果会更好。因为可能存在这样的极端:
1.代码覆盖率100%,却没有发现一个有价值的BUG
2.代码覆盖率不高,但通过很好的案例设计,发现了很有价值的BUG。
当然,我也没有完全反对使用”代码覆盖率“作为考核标准。
  
#16楼   2009-03-30 11:30  父辈的旗帜   
学习学习
  
#17楼   2009-03-30 13:57  飞林沙   
在国内,又有多少公司有精力去做这样全面的白盒测试呢?
  
#18楼   2009-03-30 16:59  Silent Void   
敲代码是一门艺术,测试代码也是一门艺术。
  
#19楼   2009-03-30 18:04  资深民工[未注册用户]
在国内是没有多少公司能做代码测试到分析在到存档的。这个肯定是白谈
  
#20楼 [ 楼主2009-03-30 18:54  CoderZh   
@Silent Void
同意!
  
#21楼   2009-03-30 19:57  施杨   
测试很重要,不过俺确很少测,这就是专业与业余的区别吧。
  
#22楼   2009-03-31 09:03  毁于随   
这里懂测试的人还挺多.(我不懂)
  
#23楼   2009-04-04 18:15  Aaron Wu   
--引用-------------------------------------------------- 
飞林沙: 在国内,又有多少公司有精力去做这样全面的白盒测试呢? 
-------------------------------------------------------- 
在我看来,现在很多测试的文章都只是空中楼阁,想法很好,实践起来就知道太难了,一个小项目要搞成高单元测试覆盖率,那是相当相当困难且费时间。
  
#24楼   2009-04-04 18:22  Aaron Wu   
--引用-------------------------------------------------- 
施杨: 测试很重要,不过俺确很少测,这就是专业与业余的区别吧。 
-------------------------------------------------------- 
这也不能就说你不专业了,只是不同的项目对于质量的要求不一样而已。 

如果是做外包项目,除非客户要求很高或者客户懂这些,质量要求自然不高,尽快交货就是了,所以测试搞得很少或者干脆搞个手工测试人员点点,写写文档就罢了。 

如果是做自己的产品,那时候质量的问题就不得不重视了。
  
#25楼   2009-04-13 16:30  xjb   
代码覆盖率是个指标,但不是唯一指标
  
#26楼 [ 楼主2009-04-13 17:07  CoderZh   
@xjb
嗯,没错
  
#27楼   2010-11-27 10:39  YaoTong   
  
#28楼   2011-07-19 11:04  天行健 自强不息   
  
#29楼   2011-09-21 10:40  heqichang   
@Nick Wang
赞成你的观点!
  
#30楼   2013-01-06 14:57  monica_cnbolgs   
楼主好文
  
#31楼   2013-08-14 11:02  勾阵   
解释的很清楚,观点也很棒!好文收藏~
  
#32楼   2013-09-06 14:37  清心朗静   
有个小问题:
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

这里的nReturn的值好像写错了。。。

文章很清晰,帮助很大,谢谢。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值