devops [持续交付实践] 基于 jacoco 的测试覆盖率统计平台实现

蒋刚毅 · 2017年09月13日 · 最后由 蒋刚毅 回复于 2017年10月16日 · 4841 次阅读
本帖已被设为精华帖!

Jacoco 简介

Jacoco 是一个开源的覆盖率工具。Jacoco 可以嵌入到 Ant 、Maven 中,并提供了 EclEmma Eclipse 插件,也可以使用 JavaAgent 技术监控 Java 程序。很多第三方的工具提供了对 Jacoco 的集成,如 sonar、Jenkins 等。
官网地址:http://www.eclemma.org/jacoco/

支持的集成工具

Jacoco 团队提供了如下的一些集成工具的支持:
Java API
http://www.eclemma.org/jacoco/trunk/doc/api/index.html
Command Line
http://www.eclemma.org/jacoco/trunk/doc/agent.html
Apache Ant
http://www.eclemma.org/jacoco/trunk/doc/ant.html
Apache Maven
http://www.eclemma.org/jacoco/trunk/doc/maven.html
Eclipse EclDmma Plugin
http://www.eclemma.org/

Jacoco 与 Eclipse 集成

打开 Eclipse 的软件市场,在其中搜索 EclEmma,找到后完成安装,如下图所示:

安装完成后,Eclipse 的工具条里会多出下面这样一个图标:

Jacoco 与 jenkins 集成

安装 jacoco 插件

Jenkins 中构建参数
关键 maven 参数:

mvn org.jacoco:jacoco-maven-plugin:prepare-agent  clean  package  -Dautoconfig.skip=true   -Dmaven.test.skip=false  -Dmaven.test.failure.ignore=true

org.jacoco:jacoco-maven-plugin:prepare-agent:命令行引用 jacoco-maven-plugin 插件,减少对开发源码的依赖。
-Dmaven.test.skip=false:启用代码中的单元测试,开发代码中一般默认是关闭的。
-Dmaven.test.failure.ignore=true:忽略失败的单元测试用例继续执行。
配置 jacoco 插件
在 “Addpost-build action” 中选择 “Reccord Jacoco coverage report”
配置文件路径:

Path to exec files :代码覆盖率统计文件位置;
Path to class directorie:classes 文件位置;
Path to source directories:源码文件位置;
根据需要填写覆盖率要求;

Jacoco 覆盖率报告

Jacoco 与 Jenkins Pipeline 集成

可视项目和团队情况,增加对测试覆盖率的要求,比如下面例子就是当代码覆盖率低于 70% 时,这个阶段将会 fail 掉。

stage('单元测试') {
steps {
echo "starting unitTest......"
//clean test. All tests should pass.
sh "mvn org.jacoco:jacoco-maven-plugin:prepare-agent -f pom.xml clean test -Dautoconfig.skip=true -Dmaven.test.skip=false -Dmaven.test.failure.ignore=true"
junit '**/target/surefire-reports/*.xml'
//code coverage.LineCoverage>70%.
jacoco changeBuildStatus: true, maximumLineCoverage:70
}
}

Jacoco 与 SonarQube 集成

jacoco report 报告路径配置

代码覆盖率统计数据

一些问题和解决方案

坑 1:使用了反射的单元测试用例执行报错:java.lang.NoSuchMethodException: com.greenline.expertpatient.model.po.EventRecordPO.set$jacocoData([Z)
解决办法:
To collect execution data JaCoCo instruments the classes under test which adds two members to the classes: A private static field $jacocoData and a private static method $jacocoInit(). Both members are marked as synthetic.
Please change your code to ignore synthetic members. This is a good practice anyways as also the Java compiler creates synthetic members in certain situation.
修改使用反射的测试用例,加个判断
if(! fields[i].isSynthetic()){
//Or whatever processing you are doing here with your fields.
}
参考链接:http://www.eclemma.org/jacoco/trunk/doc/faq.html

坑 2:multi-module maven 项目,sonarQube 只会检查指定 parent module 目录里的 jacoco.exec 覆盖率统计文件,而不会检查其他子 module 目录,即使在 sonar 里把 sonar.jacoco.reportPaths 设置成 **/**.exec 也不行(万马奔腾而过...)。
解决办法 1:
jenkins jacoco plugin 里没这个问题,代码覆盖率数据和报告可在 jenkins 上直接查看,sonarqube 的问题等待社区后续完善。
解决办法 2:
设置 jacoco 的 destFile 属性,合并所有的 jacoco.exec 报告到 multiModuleProjectDirectory 目录

<jacoco.destFile>${maven.multiModuleProjectDirectory}/target/jacoco.exec</jacoco.destFile>

${maven.multiModuleProjectDirectory}参数需要 maven 3.3.1 以上版本支持。
参考链接:https://stackoverflow.com/questions/13031219/how-to-configure-multi-module-maven-sonar-jacoco-to-give-merged-coverage-rep

主帖直达:https://testerhome.com/topics/9977

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 8 条回复 时间 点赞
蒋刚毅 回复

主要是模块较多的项目的话,source 和 class 得配很多个路径,感觉这样配置比较复杂,如果拷贝出来不影响扫描也未尝不可啊
看了下您的应该也是多模块的工程,请问您的 sonar.source 和 sonar.java.binary 是咋配的呢?也是多个路径么?

关于坑 2
我是否可以把项目的 java 和 class 文件先分别拷贝到一个目录,全部平铺开存放,去掉项目结构
然后把 jacoco.exec 也生成到 java 文件的存放目录

还是说必须扫描符合项目结构的代码,然后 jacoco.exec 也必须放在多模块项目的根目录上?

isaac 回复

移动 java 代码这个没必要吧破坏源代码结构了,如果只是想把 jacoco.exec 汇聚在一起,可以控制 jacoco.exec 的输出路径,或者运行完后把 jacoco.exec 文件收集在一起也行啊。

isaac 回复
<sonar.java.binaries>${basedir}</sonar.java.binaries>

可以这样去配,从项目根目录开始查找,sonar 那个文章里有详细说明

tzl 回复

个人资料里有 QQ,可以单独交流。

你好,请问如何在覆盖率不达标的情况下,终止后面的流程

思寒_seveniruby 将本帖设为了精华贴 10月16日 03:35
simple 专栏文章:[精华帖] 社区历年精华帖分类归总 中提及了此贴 12月13日 14:44
simple [精彩盘点] TesterHome 社区 2018 年 度精华帖 中提及了此贴 01月07日 12:08
蒋刚毅 回复

我按照文章的设置,后面的流程还是会执行,能留个联系方式么

13楼 已删除
tzl 回复

文章里有,可以再仔细看下

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册