基于BullseyeCoverage工具的代码覆盖率研究

发表于:2020-7-20 08:38

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:党珊珊    来源:51Testing软件测试网原创

  摘要:代码覆盖率是反映测试用例对被测软件覆盖程度的重要指标,既可以用于单元测试,也可以用于黑盒测试。代码覆盖率并不能表明覆盖到的代码不包含缺陷,不能完全用来衡量代码质量。但是,它可以帮我们定位到没有被测试覆盖的代码,发现测试用例的薄弱部分,进而改善测试用例。本文将通过介绍C/C++代码覆盖率测试工具BullseyeCoverage的实践,来说明一下代码覆盖率统计在测试工作中的作用。
  软件公司对软件项目的期望是在预计的时间,合理的预算下,提交一个可以交付的产品。可以交付/发布的产品并不是没有错误的产品,而是要把错误控制在一个合理的范围之内。软件测试是为了寻找软件的错误与缺陷,评估与提高软件质量。软件测试只能证明软件存在错误,而不能证明软件没有错误。想要进行完全的测试,在有限的时间和资源条件下,找出所有的软件缺陷和错误,使软件趋于完美,是不现实的。一个适度规模的程序,其路径组合近似天文数字,对于每一种可能的路径都执行一次的穷举测试是不可能的。要根据测试错误的概率以及软件可靠性要求,确定最佳停止测试时间,我们不能无限地测试下去。
  软件规模越来越大,功能越来越复杂,如何进行充分而有效的测试成为难题。在对一个软件产品进行了繁多的测试之后,我们能不能就此对软件的质量产生一定的信心呢?测试的代码覆盖率可以作为度量方式之一。虽然代码覆盖率并不能表明覆盖到的代码不包含缺陷。但是,如果测试仅覆盖了代码的一小部分,那么不管我们写了多少测试用例 ,我们也不能相信软件质量是有保证的。相反,如果测试覆盖到了软件的绝大部分代码,我们就能对软件的质量有一个合理的信心。我们可以通过代码覆盖率工具定位到未被测试覆盖的代码,发现测试的薄弱部分,补充测试用例,使我们的测试更加充分。
  1 理论基础
  代码覆盖(Code Coverage)是软件测试中的一种度量,描述程序中源代码被测试的比例和程度,所得比例称为代码覆盖率。衡量代码覆盖程度的指标有很多,常用的有函数覆盖,语句覆盖,判断覆盖,条件覆盖和路径覆盖。下面简单介绍一下各覆盖率的含义:
  函数覆盖(Function Coverage):执行到程序中的每一个函数。
  语句覆盖(Statement Coverage):又称行覆盖,就是度量被测代码中每个可执行语句是否被执行到了。语句覆盖常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合等。
  判断覆盖(Decision Coverage):又称分支覆盖(Branch Coverage),基本路径覆盖(Basic Path Coverage)。它度量程序中每一个判定的分支是否都被测试到了。
  条件覆盖(Condition Coverage):它度量判定中的每个子表达式结果true和false是否被测试到了。条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个条件表达式的结果true和false测试到了就好了。因此,我们可以推出:完全的条件覆盖并不能保证完全的判断覆盖。
  路径覆盖(Path Coverage):又称断言覆盖(Predicate Coverage)。它度量了是否函数的每一个分支都被执行了。有多个分支嵌套时,需要对多个分支进行排列组合。被认为是“最强的覆盖”
  2 工具介绍
  BullseyeCoverage是Bullseye公司提供的一款C/C++代码覆盖率测试工具。除了支持各种Unix下的编译器之外,在Windows下支持VC, Borland C++, Gnu C++, Inter C++。提供的代码覆盖率是条件/分支覆盖率。
  BullseyeCoverage采用的是先对代码进行“插桩”,然后收集覆盖数据,最后分析覆盖率的技术,其工作原理是:针对不同的编译器,设计一个和真实编译器同名的拦截器(拦截器文件存放在BullseyeCoverage的bin目录下),当覆盖编译开关打开时,C/C++源文件在编译过程中将首先被这些拦截器拦截,由拦截器将一系列探针代码插入到源文件中,然后源文件再通过真实的编译器生成能够被Bullseye Coverage分析的二进制文件,当程序被执行时,代码覆盖的情况会被自动记录到指定的cov 文件中去,通过一些命令能够从该文件中获取代码和条件/分支覆盖的情况。
  代码覆盖率是一个白盒概念,那么是不是只有白盒测试才能统计代码覆盖率呢?使用BullseyeCoverage工具,即使没有源代码,也能统计出代码覆盖率。也就是说,功能测试或者黑盒测试同样能够统计代码覆盖率。但是如果要查看某个函数中具体条件/分支的执行情况,就必须在有代码的机器上进行分析。
  BullseyeCoverage的安装很简单,大部分地方只需根据默认进行安装。但要注意到Coverage File Path这一步时,根据需要更改cov文件的存放路径。
  BullseyeCoverage与Visual Studio的集成比较好。工具安装后,在Visual Studio工具菜单中将会增加Enable /Disable BullseyeCoverage Build选项。用Visual Studio编译程序前,勾选Enable BullseyeCoverage Build选项。编译完成后,运行测试程序,覆盖率就会自动记录到cov文件中,打开工具加载cov文件,就可以直观看到统计数据。覆盖率统计的结果还可以保存成html格式,在没安装工具的电脑上,也很方便查看。
  如果要把编译完的程序,拷到其它测试机来运行和统计覆盖率,那么测试机也需要安装BullseyeCoverage工具,将编译时生成的cov文件拷到测试机安装BullseyeCoverage时指定的cov存放目录就好了。
  对于比较复杂的项目,需要多人同时完成测试时,可以利用该工具的合并功能将每个人测得的cov文件进行合并,得到一个总的覆盖率文件。具体方法为:将各cov文件都放到cov存放目录,打开cmd,输入 covmerge -c -f total.cov test1.cov test2.cov命令,得到的total.cov就可以用来查看总的覆盖率。
  3 实践应用
  本文以视频车检器的配置软件测试为例,简单介绍一下BullseyeCoverage工具在测试C++程序时的应用。
  执行视频车检器的配置软件的测试之后,打开BullseyeCoverage工具,点击刷新图标,工具就会对测试的代码覆盖情况进行显示,其中蓝色部分代表已经覆盖到的代码,红色部分代表未覆盖的代码。代码覆盖率分两种级别,函数覆盖率和条件/分支覆盖率,可以分别对模块,文件进行统计。
  本次实践中,对模块的覆盖率统计:
  各文件的代码覆盖率统计:
  得到覆盖率后,如何用它来完善测试用例呢?
  举一个简单的例子说明这个过程。
  做完一轮测试后,发现如下几个文件没有执行到:
  根据文件的命名和对产品功能的基本了解,由PropertyPresetBitDlg.cpp 和PresettingBit.cpp 两个文件,推测出是车检器的预置位漏测了。于是设置了预置位来进行验证。设置后的统计结果:
  可见PresettingBit.cpp 已经达到了100%,而PropertyPresetBitDlg.cpp函数覆盖率达到了80%,条件/分支覆盖率只有16%。我们可以打开文件分析下具体什么函数没被执行到。
  由上图可见OnBnClickedButtonSwitch()没有执行,推测是一个切换功能的按钮没有点击。补充切换按钮的测试后:
  以上是文件和函数级别的覆盖率提高,就算没有代码,也可以做到。如果有代码的话,还可以看到函数中哪个条件/分支没有执行。点击具体函数,查看函数实现,工具中有具体图标指示执行情况,在代码行标左边标出,图标含义为:
  √ 表示已执行过该函数;
  →表示该函数(判定分支/表达式)未被执行。
  →T表示只执行过该判定分支为真的情况;
  →F表示只执行过该判定分支为假的情况;
  TF表示该判定分支的真假两种情况均被执行过;
  →t表示只执行过该表达式为真的情况;
  →f表示只执行过该表达式为假的情况;
  tf 表示该表达式的真假两种情况均被执行过;
  举例说明:
  由上图可以看出,小于最小值或大于最大值的条件分支还没有执行过,即给定数值范围的无效值还没有测试过。补充该项测试后,该函数左边的图标发生改变,表明该分支已经被执行。
  测试人员通过以上步骤对文件,函数,条件/分支的分析,对用例进行完善后,可能发现还是有一些文件没执行到,这时可以和研发讨论,这些文件是否有用,有用的话什么情况下会被执行。当然还可以进一步请教已执行文件中条件/分支覆盖率低的原因。本例中经过与研发确认,未被执行的文件中,除了HistoryEdit.h,其他4个文件都没有用。对于与研发确认过,在工程中没用到又没有进行删除的文件,可以不计入统计。方法:选中文件,右键选择Exclude. 被Exclude的文件上会有个“/”标记,想重新包含时,右键选择include即可恢复。
  最终,本例中代码覆盖率的统计结果为:
  4 作用及建议
  得到代码覆盖率之后,对使用它的步骤进行归纳:
  1) 根据测试人员对产品已有的了解,以及文件命名,函数命名来推测,未被执行的文件和函数是什么功能相关的,然后执行这些功能。
  2) 如果对代码有一定了解的话,可以打开具体某个函数,看一下条件/分支覆盖率是否还能再提高。
  3) 由前面步骤提高一部分覆盖率后,如果还有未被执行的文件,函数的话,可以请教研发人员这些文件,函数是否确实有用,有用的话,在什么情况下会执行到,然后测试这些情况,使覆盖率进一步提高。对于确实没用的代码,建议研发进行删除。
  通过对代码覆盖率的使用,分析出它的作用:
  1) 把测试覆盖率作为质量目标的意义并不大,我们应该把它作为一种发现未被测试覆盖的代码的手段,进而完善测试用例。
  2) 能检测出程序中的废代码,可以逆向反推在代码设计中的思维混乱点,提醒设计/开发人员理清代码逻辑关系,提升代码质量。
  代码覆盖率统计的建议:
  如果要统计完整的代码覆盖率,就需要完整的执行一遍测试用例。所以,代码覆盖率的统计是比较耗资源的一项工作,尤其是测试的自动化程度不高的话,代价会很高。既然代码覆盖率的意义主要是为了完善测试用例,那么就不需要在每次测试的时候都统计。在回归测试的时候统计的意义不大,在系统测试的初始阶段,和增加新功能的版本测试时,最好来统计一下,这样就可以尽早地定位到我们测试用例的薄弱环节,进而完善测试用例。
  结束语
  本文通过对测试覆盖率的分析及BullseyeCoverage工具的应用实例,阐述了代码覆盖率的统计方法及意义。白盒测试和黑盒测试都能统计代码覆盖率,区别是白盒能看到具体哪些条件/分支没被执行到。我们追求的不是100%的代码覆盖率,因为代码覆盖率统计不能完全用来衡量代码质量,代码覆盖率统计是用来发现没有被测试覆盖的代码,通过分析代码覆盖率的统计情况,来发现测试中遗漏的部分,进而补充和完善测试用例,使测试更加充分,对交付的产品更加放心。


版权声明:本文出自《51测试天地》第五十八期。51Testing软件测试网及相关内容提供者拥有51testing.com内容的全部版权,未经明确的书面许可,任何人或单位不得对本网站内容复制、转载或进行镜像,否则将追究法律责任。
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号