随着敏捷开发的流行,编写单元测试已经成为业界共识。但如何来衡量单元测试的质量呢?有些管理者片面追求单元测试的数量,导致底下的开发人员投机取巧,编写出大量的重复测试,数量上去了,质量却依然原地踏步。相比单纯追求单元测试的数量,分析单元测试的代码覆盖率是一种更为可行的方式。JaCoCo(Java Code Coverage)就是一种分析单元测试覆盖率的工具,使用它运行单元测试后,可以给出代码中哪些部分被单元测试测到,哪些部分没有没测到,并且给出整个项目的单元测试覆盖情况百分比,看上去一目了然。EclEmma 是基于 JaCoCo 的一个 Eclipse 插件,开发人员可以方便的和其交互。因此,本文先从 EclEmma 入手,给读者一个直观的体验。
1、什么是JaCoCo
JaCoCo是一个开源的覆盖率工具,它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。
插桩:程序插桩,它是在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针(又称为“探测仪”,本质上就是进行信息采集的代码段,可以是赋值语句或采集覆盖信息的函数调用),通过探针的执行并抛出程序运行的特征数据,通过对这些数据的分析,可以获得程序的控制流和数据流信息,进而得到逻辑覆盖等动态信息,从而实现测试目的的方法。
On-the-fly插桩:JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序,代理程序在通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析可以在JVM执行测试代码的过程中完成。
Offline模式:在测试前先对文件进行插桩,然后生成插过桩的class或jar包,测试插过桩 的class和jar包后,会生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。
2、什么是代码覆盖
测试过程中根据需求文档和设计文档编写测试用例、执行测试;为了更加全面的覆盖,我们可能还需要理解被测程序的逻辑,需要考虑到每个函数的输入与输出,逻辑分支代码的执行情况,这个时候我们的测试执行情况就以代码覆盖率来衡量,可以理解为白盒覆盖。
以上两者完全可以相辅相成,用代码覆盖结果反向的检查需求覆盖(用例)的测试是否充分完整。
3、JaCoCo在eclipse里头的使用
在Eclipse Marketplace中寻找EclEmma插件
查找EclEmma:
安装插件:
新建一个java工程,编写代码:
public class JacocoTest { public static void main(String[] args) { int rand=(int)(Math.random()*100); if(rand%2==0){ System.out.println("helloWorld 0"); }else{ System.out.println("helloWorld 1"); } int result=rand%2==0?rand+rand:rand*10; System.out.println(result); } }
右键coverage as Java application
可以看到效果如下:
标示绿色的为分支覆盖充分,标黄色的为部分分支覆盖,标红色的为未执行该分支。
查看测试率,Window->Show View->Other->Java->Coverage
Project Explorer中查看覆盖率,Window->Preferences->General->Appearence->Label Decorations,选中Java Code Coverage。
生成覆盖率报告
File->Export->Run/Debug>Coverage Session->选择需要生成报告的测试源以及目标地址
导出html格式
效果如图:
我们在这里并不是为了单纯的追求这个数字,在增加单元测试覆盖率的诱导下,我们重新理清了测试的步骤,写出了更有意义、更全面的单元测试。而且根据单元测试分析工具给的反馈,我们还发现了先前没有想到的情形。因此,单元测试的覆盖率并不只是一个为了取悦管理者的数据,它实实在在地帮助我们改善了代码的质量,增加了我们对所编写代码的信心。在单元和系统测试过程中,其常常被拿来作为衡量测试好坏的指标,甚至很多情况下用代码覆盖率来考核测试任务完成情况,经常会被要求代码覆盖率必须达到XX%以上,才算测试充分,于是乎测试人员或者开发人员费尽心思设计案例来覆盖代码,这种用代码覆盖率来衡量,有利也有弊。
一些忠告:
1、覆盖率数据只能代表你测试过哪些代码,不能代表你测好这些代码。
2、不要过于相信覆盖率数据。
3、不要只拿语句/行覆盖来衡量
4、路径覆盖率>判断覆盖>语句覆盖
5、不要盲目的为了提供覆盖率而补充用例,应该想办法设计更好的用例,哪怕多设计的用例对覆盖率提升没有效果。