加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

如何提高代码的稳定性与可靠性------代码覆盖率浅谈

(2011-12-16 05:19:57)
标签:

覆盖率

测试人员

代码

判定

分支

杂谈

分类: 稳定性与可靠性

代码覆盖率浅谈

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

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

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

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

1. 语句覆盖(StatementCoverage)

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

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

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


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

TeseCase: = 10= 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 || < 10// 判定
    {
        
return 0// 分支一
    }
    
else
    {
        
return 1// 分支二
    }
}


设计判定覆盖案例时,我们只需要考虑判定结果为true和false两种情况,因此,我们设计如下的案例就能达到判定覆盖率100%:

TestCaes1: = 5= 任意数字  覆盖了分支一
TestCaes2: 
= 15= 15          覆盖了分支二

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

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


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

TestCase1: = 5= 15  true,  false   分支一
TestCase1: 
= 15= 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 = 5= 5   nReturn = 11

 语句覆盖率100%


b. 判定覆盖

TestCase1 a = 5 = 5     nReturn = 11

TestCase2 a = 15= 15   nReturn = 0

判定覆盖率100% 


c. 条件覆盖

TestCase1 a = 5 = 15   nReturn = 1

TestCase2 a = 15= 5     nReturn = 10

条件覆盖率100% 

 

我们看到,上面三种覆盖率结果看起来都很酷!都达到了100%!主管可能会非常的开心,但是,让我们再去仔细的看看,上面被测代码中,nReturn的结果一共有四种可能的返回值:0,1,10,11,而我们上面的针对每种覆盖率设计的测试案例只覆盖了部分返回值,因此,可以说使用上面任一覆盖方式,虽然覆盖率达到了100%,但是并没有测试完全。接下来我们来看看针对路径覆盖设计出来的测试案例:

TestCase1 a = 5  = 5     nReturn = 0

TestCase2 a = 15= 5     nReturn = 1

TestCase3 a = 5  = 15   nReturn = 10

 

TestCase4 a = 15= 15   nReturn = 11

路径覆盖率100% 


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

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

总结

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

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

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

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

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

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

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

posted @ 2009-03-29 14:45 CoderZh 阅读(7968) 评论(29) 编辑 收藏
http://www.cnblogs.com/coderzh/aggbug/1424344.html?type=1&webview=1

发表评论
 回复 引用   
#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      
Mark
 回复 引用 查看   
#28楼 2011-07-19 11:04 天行健 自强不息      
好文
 回复 引用 查看   
#29楼 2011-09-21 10:40 heqichang      
@Nick Wang
赞成你的观点!


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有