了解Jacoco

Jacoco是由Eclipse发行,用于计算Java代码覆盖率的免费开源工具包。Eclipse EclEmma在2.0版本之前集成的是EclEmma团队基于EMMA开发的代码覆盖工具,之后的版本都是基于Jacoco的。

产品定义
  • 特征
    指令(C0),分支(C1),行,方法,类型和圈复杂度的覆盖率分析。
    基于Java字节码,因此无需源文件也可以工作。
    通过基于Java的即时工具进行简单集成。
    其他集成方案(例如自定义类加载器)也可以通过API来实现。
    与框架无关的:与基于Java VM的应用程序(如纯Java程序,OSGi框架,Web容器或EJB服务器)平滑集成。
    与所有已发布的Java类文件版本兼容。
    支持不同的 JVM语言。
    几种报告格式(HTML,XML,CSV)。
    远程协议和JMX控制可在任何时间点从coverage代理请求执行数据转储。
    支持Ant任务收集和管理执行数据并创建结构化的覆盖率报告。
    支持Maven插件收集覆盖率信息并在Maven构建中创建报告。
  • 非功能特性
    简单的用法以及与现有构建脚本和工具的集成。
    良好的性能和最小的运行时开销,尤其是对于大型项目。
    轻量级实现,对外部库和系统资源的依赖性最小。
    完善的 JavaDoc文档 和 与其他工具集成的demo。
    回归测试全功能测试覆盖率基于 JUnit的测试用例。

下面举例简单介绍一些其他的免费Java代码覆盖率工具

工具

介绍

覆盖类型

结果统计

EMMA

基于Java字节码检测的Java覆盖工具,速度快,因无更新eclipse已废弃

类,方法,行,基本块

支持在<方法,类,行,基本块,包和所有类>级别汇总;报告支持纯文本,HTML,XML

Jcov

基于Java字节码检测的开源Java覆盖工具,有动态和静态两种方式,现用于OpenJdk中

基本块,方法,分支,行

基于测试套件生成单个报告,可合并,报告支持HTML,XML

Serenity

自动化验收测试工具,除了基于Java字节码检测的代码覆盖,还支持代码度量–圈复杂度,稳定性等

基本块,方法,分支,行

报告结果可通过Jenkins或ide展示

Cobertura

基于Java字节码检测的开源Java覆盖工具

类,行,分支

报告支持HTML,XML

虽然有很多的工具,也是大同小异了,但我们大都最终选择Jacoco,简单易用并且轻量级肯定是首要原因,维护也比较积极。但每个工具都有自己的坑,等待我们去跳去吐槽~

Gradle Jacoco Plugin 使用

1. 引入Jacoco插件

直接在需要覆盖率的项目(project)中引用即可

apply plugin: 'jacoco'

Note:

  • 项目中引入插件后,一个新的名为jacocoTestReport的任务会默认存在。
  • 在执行测试文件后要手动执行任务jacocoTestReport,因为任务jacocoTestReport不依赖于任务test。另一种方式就是重写任务jacocoTestReport,让其依赖于任务test
  • 默认生成的是HTML的报告,默认路径$buildDir/reports/jacoco/test
2. 配置Jacoco插件

以下是Jacoco插件提供的拓展任务(type为JacocoPluginExtension),可以让我们使用其提供的默认值配置,我们也可以根据自身情况覆盖其中的一些属性。

jacoco {
    toolVersion = "0.8.5"
    reportsDir = file("$buildDir/customJacocoReportDir")
}

toolVersion不填,会取当前插件的默认jacoco版本,试了下在grade4.8下取的是 jacoco 0.8.0 版本的jar。
reportsDir不填,会取默认路径$buildDir/reports/jacoco

3. 配置Jacoco报告参数

以下的jacocoTestReport是默认存在的类型为JacocoReport的任务,可以用于生成不同格式的代码覆盖率报告,默认生成任务所在模块的代码覆盖率。
如果想要有定制化需求,可建个新的类型为JacocoReport任务使用。

jacocoTestReport {
    reports {
        xml.enabled false
        csv.enabled false
        // 报告的生成位置
        html.destination file("${buildDir}/jacocoHtml")
    }
}

以上配置好就可以在报告生成路径(${buildDir}/jacocoHtml)下看到报告啦,以下为html的报告图示

jenkins构建gradle项目_jenkins构建gradle项目

4. 覆盖率合并计算–JacocoMerge(合并报告)

可以通过下图了解下这几个Jacoco插件Task的组成。Reporting 和 ReportContainer 是gradle提供的覆盖率报告接口,其他覆盖率工具应该也是通过此接口来实现功能,JacocoReport和JacocoReportsContainer 分别实现了这两个接口,JacocoMerge是Jacoco插件单独提供的功能。

jenkins构建gradle项目_jenkins构建gradle项目_02


多模块项目,或者一个项目中有多个Test任务,会生成多个exec文件(exec文件会以Test任务的名字命名),我们如果想要合并它们,就可以用JacocoMerge。

创建一个type为jacocoMerge的任务,这个任务需要我们手动执行,一般会让JacocoReport依赖其执行,而且要让Test任务先于其执行。总结来说它们的执行顺序从先到后为:Test > JacocoMerge > JacocoReport 。

以下为JacocoMerge的示例,JacocoMergeexecutionData:待合并的exec文件列表,JacocoMergedestinationFile:要写入合并的exec数据的文件,JacocoReportexecutionData:指定报告要分析的exec数据文件路径。注意executionData = xxx的这种写法是set(直接覆盖原值),executionData xxx的这种写法是在原值基础上追加文件。

task jacocoMerge(type: JacocoMerge, dependsOn: [testTask1, testTask2]) {
    File jacocoFile = file("$buildDir/jacoco/jacoco.exec")
    // 删除上一次生成的合并文件jacoco.exec
    doFirst {
        jacocoFile.delete()
    }
    // 待合并列表加入当前模块下的exec文件
    executionData files {
        file("$buildDir/jacoco").listFiles()
    }
    // 待合并列表加入另一个模块services生成的exec文件
    executionData files {
        file(project(":services").buildDir.path + "/jacoco").listFiles()
    }
    destinationFile = jacocoFile
}

// 在 3 步骤上进行补充配置
jacocoTestReport(dependsOn: jacocoMerge) {
    // 指定上面jacocoMerge生成合并后的exec文件(不指定的话会默认取$buildDir/jacoco/test.exec)
    executionData = "$buildDir/jacoco/jacoco.exec"
    // 添加service模块的源码进入覆盖率报告
    sourceSets project(":services").sourceSets.main
    reports {
        xml.enabled false
        csv.enabled false
        html.enabled true
    }
}

Jenkins Jacoco Plugin 使用

安装

Jenkins安装Jacoco插件

jenkins构建gradle项目_jenkins构建gradle项目_03

使用

Jenkins Jacoco插件可以作为构建后步骤中的一部分,通过build项目生成的exec文件,来记录并展示覆盖率数据,还可以在项目主页面上以图表的方式展示覆盖率趋势。

覆盖率报告配置

要启用Jacoco插件,只需要在构建后步骤(Post-build Actions)中添加一项Record Jacoco coverage report,Jenkins Jacoco覆盖率报告配置即可。

jenkins构建gradle项目_Java_04


jenkins构建gradle项目_jenkins构建gradle项目_05


配置说明

  • exec配置
    Path to exec files(e.g.: **/target/**.exec, **/jacoco.exec): 填入构建项目时Jacoco生成的exec文件(本文示例填:在上面提到过的合并后的jacoco.exec)
  • class配置(算入覆盖率的class文件)
    Inclusions (e.g.: **/*.class): 要计算覆盖率的class文件。
    Exclusions (e.g.: **/*Test*.class): 排除不需要计算覆盖率的class文件。
    Path to class directories (e.g.: **/target/classDir, **/classes): 要计算覆盖率的class目录,即源码编译后生成的目录
  • source配置(用于查看源码文件详细覆盖率)
    Path to source directories (e.g.: **/mySourceFiles): 要查看覆盖率的源码目录。
    Inclusions (e.g.: **/*.java,**/*.groovy,**/*.gs): 指明要查看覆盖率的源码文件。
    Exclusions (e.g.: generated/**/*.java): 排除不需要查看覆盖率的源码文件。
    Disable display of source files for coverage: 不展示源码覆盖率。选中此选项会让source配置失效。
  • 根据阈值更改构建状态
    Change build status according the thresholds: 大于晴天行(第一行)的值则构建状态为success;位于晴天行(第一行)和雷雨天行(第二行)之间的值则构建状态为unstable;小于雷雨天行(第二行)的值则构建状态为fail。可选是否激活此功能。
  • 覆盖率降低的值超过增量阈值则构建失败
    Fail the build if coverage degrades more than the delta thresholds: 覆盖率波动值低于所填值则构建状态为fail。可选是否激活此功能。

运行项目

配置好后启动项目,就可以在控制台(Console Output)中看到Jacoco Plugin的执行输出。

[JaCoCo plugin] Collecting JaCoCo coverage data...
[JaCoCo plugin] **/jacoco.exec;**/build/classes;**/src/main/java; locations are configured
[JaCoCo plugin] Number of found exec files for pattern **/jacoco.exec: 1
[JaCoCo plugin] Saving matched execfiles:  /var/jenkins_home/workspace/test2/api/build/jacoco/jacoco.exec
[JaCoCo plugin] Saving matched class directories for class-pattern: **/build/classes: 
[JaCoCo plugin]  - /var/jenkins_home/workspace/test2/api/build/classes 24 files
[JaCoCo plugin]  - /var/jenkins_home/workspace/test2/common/build/classes 5 files
[JaCoCo plugin]  - /var/jenkins_home/workspace/test2/model/build/classes 39 files
[JaCoCo plugin]  - /var/jenkins_home/workspace/test2/services/build/classes 88 files
[JaCoCo plugin] Saving matched source directories for source-pattern: **/src/main/java: 
[JaCoCo plugin] Source Inclusions: **/*.java
[JaCoCo plugin] Source Exclusions: 
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/admin/src/main/java 25 files
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/api/src/main/java 14 files
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/common/src/main/java 5 files
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/contract/src/main/java 29 files
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/model/src/main/java 19 files
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/sdk/src/main/java 3 files
[JaCoCo plugin] - /var/jenkins_home/workspace/test2/services/src/main/java 59 files
[JaCoCo plugin] Loading inclusions files..
[JaCoCo plugin] inclusions: [**/*.class]
[JaCoCo plugin] exclusions: [**/com/xingren/*/model/**, **/test/**/**Test.class]
[JaCoCo plugin] Thresholds: JacocoHealthReportThresholds [minClass=0, maxClass=0, minMethod=0, maxMethod=0, minLine=0, maxLine=0, minBranch=0, maxBranch=0, minInstruction=0, maxInstruction=0, minComplexity=0, maxComplexity=0]
[JaCoCo plugin] Publishing the results..
[JaCoCo plugin] Loading packages..
[JaCoCo plugin] Done.
[JaCoCo plugin] Overall coverage: class: 89, method: 71, line: 78, branch: 60, instruction: 73
Finished: SUCCESS

查看结果

添加了覆盖率配置构建后,在项目主页上会有一个图表展示。可以点击进去看具体源代码覆盖率。

jenkins构建gradle项目_Test_06

在Jenkins项目列表页可通过编辑视图去配置 分支和行覆盖率 的显示。这两列数据的显示颜色会根据覆盖率的数值变化。

jenkins构建gradle项目_java_07


jenkins构建gradle项目_Java_08

jenkins构建gradle项目_Test_09