Java代码覆盖率历史发展轨迹

简介: Java代码覆盖率历史发展轨迹

0 覆盖率定义

作为一个测试人员,保证产品的软件质量是其工作首要目标,为了这个目标,测试人员常常会通过很多手段或工具来加以保证,覆盖率就是其中一环比较重要的环节。

我们通常会将测试覆盖率分为两个部分,即“需求覆盖率”和“代码覆盖率”。


需求覆盖:指的是测试人员对需求的了解程度,根据需求的可测试性来拆分成各个子需求点,来编写相应的测试用例,最终建立一个需求和用例的映射关系,以用例的测试结果来验证需求的实现,可以理解为黑盒覆盖。

代码覆盖:为了更加全面的覆盖,我们可能还需要理解被测程序的逻辑,需要考虑到每个函数的输入与输出,逻辑分支代码的执行情况,这个时候我们的测试执行情况就以代码覆盖率来衡量,可以理解为白盒覆盖。

以上两者完全可以相辅相成,用代码覆盖结果反向的检查需求覆盖(用例)的测试是否充分完整。


java中比较流行的代码覆盖率工具有EMMA,Cobertura,jacoco等。其实以现在情况来看,使用jacoco的人群是比较多的,有点大势所趋的感觉。

1 EMMA

本来以前用EMMA的人很多,但是开发这个工具的坑爹团队自从2006年后就再也没更新过了

6.png

可以理解为EMMA已die。

  • maven 仓库也没啥更新了
  • 7.png
  • 以后肯定会被淘汰的
    不过EMMA使用起来确实太简单了,新手首选。
    通过查询古籍,发现此前 IDEA 也是支持的,现在已不再支持.

1.1 maven 集成

java项目大多都是用maven管理的,如果我们想统计单元测试的覆盖率的话,通过emma与maven集成是最简单不过的。不像jacoco那么麻烦,配置emma十分简单。只需要添加如下依赖:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>emma-maven-plugin</artifactId>
    <version>1.0-alpha-3</version>
    <inherited>true</inherited>
</plugin>

然后运行命令:mvn emma:emma。 之后你就可以看report了

1.2 与jenkins集成

如果你使用jenkins作为CI的工具的话,其实就更简单了。你都不用再pom文件中增加依赖,安装好EMMA的插件以后,直接运行上面的例子的命令就好了。

1.3 插桩

上面介绍的都只能统计项目本身的测试,也就是在工程中的src/test/java包下面的测试脚本。如果是我们的接口测试,UI测试呢?我们怎么做才能统计代码覆盖率呢?这就需要一些手段了。


首先,你需要从官网中下载emma.jar到你的测试环境中,然后copy到你的jre的ext文件夹中。这样就是扩展了java命令,以后你就可以直接以java emma的形式执行操作了。

然后你需要对被测的包进行插桩。然后emma会开启一个服务,默认端口47653。这个服务就会监控被测的工程了。插桩的例子如下。具体的命令参数大家参照官网就好。

java emma instr -m overwrite -cp simba-1.0.jar -out coverage.em

最后就是收集报告了。这里需要两个命令,一个是收集数据,一个是生成报告。例子如下。着重说一下几个参数。-sp是你源代码的路径,这样emma才能获取代码信息展示更详细的报告。-in是生成报告需要的元数据信息。是在插桩和收集数据生成的中间文件。-r是report的格式。这几个参数是常用的。

java emma ctl -connect localhost:47653 -command coverage.get,coverage.ec
java emma report -r html -Dreport.out.encoding=utf-8 -sp /opt/web/simba/src/main/java -in coverage.em,coverage.ec

只要你不删除插桩和收集数据所产生的元数据文件的话。你都可以累计的生成报告。还有一个merge模式可以合并报告,详细的东西大家可以去官网看一下。EMMA的好处就是使用简单。最后我发一个生成的报告的图吧。

8.png

EMMA有一个坑就是在jdk1.6以上的版本有可能出现一个问题,插桩之后运行会出现一个classformat异常。提示你参数数量不正确,大概是这个意思吧。其实这是jdk在1.7以后使用的验证器不一样了。而EMMA这个坑爹货太久没有更新了,根本没cover到新版本的JDK。所以需要我们在启动jvm的时候增加一个参数。-XX:-UseSplitVerifier。这样就可以了。这个坑当时着实坑了我俩小时。

总结

即使达到100%的覆盖率也不能保障你的产品质量

但是覆盖率过低的产品的质量一定是不能被保障的

真正重视代码覆盖率,把它加入到质量保证的流程中。否则很容易变成摆设

提高测试人员的代码水平,熟悉产品代码。否则也容易变成摆设

不要妄图做到100%,那不可能。

保持一个覆盖率的平衡:单元测试50%70%,接口20%40%,UI10%

尽可能劝说开发人员写单元测试。越是底层的测试,实现覆盖的成本越低。妄图在测试人员这边达到高覆盖率几乎是不可能的

如果没有单元测试。尽量在接口测试中提高覆盖率

2 jacoco

jacoco就是 EMMA 的团队开发的 他们已经全部转向jacoco

9.png

JaCoCo优势

  • JaCoCo支持分支覆盖、引入了Agent
  • EMMA官网已经不维护了,JaCoCo是其团队开发的,可以理解为一个升级版
  • JaCoCo社区比较活跃,github 上也在不断的维护更新
  • 10.png
  • 它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。

很多第三方的工具提供了对JaCoCo的集成,如sonar、Jenkins等。

JaCoCo包含了多种尺度的覆盖率计数器,包含指令级覆盖(Instructions,C0coverage),分支(Branches,C1coverage)、圈复杂度(CyclomaticComplexity)、行覆盖(Lines)、方法覆盖(non-abstract methods)、类覆盖(classes)

JaCoCo基本概念

行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。

类覆盖率:度量计算class类文件是否被执行。

分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的

总分支数,确定执行和不执行的 分支数量。

方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。

指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。

圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目

JaCoCo 原理

只针对 class 文件,并不需要源文件

11.png

注入方式

12.png

JaCoCo在Byte Code时使用的ASM技术修改字节码方法,可以修改Jar文件、class文件字节码文件。

JaCoCo同时支持on-the-fly和offline的两种插桩模式

On-the-fly插桩:

JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序,代理程序在通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析可以在JVM执行测试代码的过程中完成。

Offline模式:

在测试前先对文件进行插桩,然后生成插过桩的class或jar包,测试插过桩 的class和jar包后,会生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。

On-the-fly和offline比较:

On-the-fly模式更方便简单进行代码覆盖分析,无需提前进行字节码插桩,无需考虑classpath 的设置。

存在如下情况不适合on-the-fly,需要采用offline提前对字节码插桩:


(1)运行环境不支持java agent。


(2)部署环境不允许设置JVM参数。


(3)字节码需要被转换成其他的虚拟机如Android Dalvik VM。


(4)动态修改字节码过程中和其他agent冲突。


(5)无法自定义用户加载类。


JaCoCo执行最小需要Java5

JaCoCo通过注入来修改和生成java字节码,使用的是ASM库。

使用

ant

不再赘述

maven 项目插件

这种方式适合Maven的项目。

调用流程:

(1) 项目已jar包方式打包,引入junit和jacoco。

(2) Build时执行instrument、report、check。

(3) 覆盖率生成到target/jacoco.exec

3 总结

13.png

推荐链接

http://openclover.org/doc/manual/latest/general–comparison-of-code-coverage-tools.html

参考

https://cloud.tencent.com/developer/article/1038055



目录
相关文章
|
15天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
2月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
63 2
|
2月前
|
存储 Java API
键值对魔法:如何优雅地使用Java Map,让代码更简洁?
键值对魔法:如何优雅地使用Java Map,让代码更简洁?
124 2
|
2月前
|
安全 Java API
Java 17新特性让你的代码起飞!
【10月更文挑战第4天】自Java 8发布以来,Java语言经历了多次重大更新,每一次都引入了令人兴奋的新特性,极大地提升了开发效率和代码质量。本文将带你从Java 8一路走到Java 17,探索那些能让你的代码起飞的关键特性。
83 1
|
1月前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
40 5
Java反射机制:解锁代码的无限可能
|
26天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
60 3
|
1月前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
87 10
|
2月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
82 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
27天前
|
分布式计算 Java MaxCompute
ODPS MR节点跑graph连通分量计算代码报错java heap space如何解决
任务启动命令:jar -resources odps-graph-connect-family-2.0-SNAPSHOT.jar -classpath ./odps-graph-connect-family-2.0-SNAPSHOT.jar ConnectFamily 若是设置参数该如何设置
|
25天前
|
Java
Java代码解释++i和i++的五个主要区别
本文介绍了前缀递增(++i)和后缀递增(i++)的区别。两者在独立语句中无差异,但在赋值表达式中,i++ 返回原值,++i 返回新值;在复杂表达式中计算顺序不同;在循环中虽结果相同但使用方式有别。最后通过 `Counter` 类模拟了两者的内部实现原理。
Java代码解释++i和i++的五个主要区别