Intro to JaCoCo – JaCoCo介绍

最后修改: 2016年 8月 6日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Code coverage is a software metric used to measure how many lines of our code are executed during automated tests.

代码覆盖率一种软件指标,用于衡量我们的代码在自动测试期间有多少行被执行。

In this tutorial, we’re going to stroll through some practical aspects of using JaCoCo, a code coverage reports generator for Java projects.

在本教程中,我们将漫步于使用JaCoCo,Java项目的代码覆盖率报告生成器的一些实践方面。

2. Maven Configuration

2.Maven配置

In order to get up and running with JaCoCo, we need to declare this maven plugin in our pom.xml file:

为了使用JaCoCo,我们需要在我们的pom.xml文件中声明这个maven插件>。

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.7.201606060606</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The link provided here will always go to the latest version of the plugin in the maven central repository.

这里提供的链接将始终指向maven中央仓库中的最新版本的插件。

3. Code Coverage Reports

3.代码覆盖率报告

Before we start looking at JaCoCo’s code coverage capabilities, we need to have a code sample. Here’s a simple Java function that checks whether a string reads the same backward and forward:

在我们开始研究JaCoCo的代码覆盖能力之前,我们需要有一个代码样本。这里有一个简单的Java函数,检查一个字符串的前后读数是否相同。

public boolean isPalindrome(String inputString) {
    if (inputString.length() == 0) {
        return true;
    } else {
        char firstChar = inputString.charAt(0);
        char lastChar = inputString.charAt(inputString.length() - 1);
        String mid = inputString.substring(1, inputString.length() - 1);
        return (firstChar == lastChar) && isPalindrome(mid);
    }
}

Now all we need is a simple JUnit test:

现在我们所需要的是一个简单的JUnit测试。

@Test
public void whenEmptyString_thenAccept() {
    Palindrome palindromeTester = new Palindrome();
    assertTrue(palindromeTester.isPalindrome(""));
}

Running the test using JUnit will automatically set in motion the JaCoCo agent. It will create a coverage report in binary format in the target directory, target/jacoco.exec.

使用 JUnit 运行测试将自动启动 JaCoCo 代理。它将在目标目录target/jacoco.exec.中创建一个二进制格式的覆盖报告。

Obviously we can’t interpret the output single-handedly, but other tools and plugins can, e.g. Sonar Qube.

显然,我们不能单枪匹马地解释输出,但其他工具和插件可以,例如Sonar Qube

The good news is that we can use the jacoco:report goal in order to generate readable code coverage reports in several formats, like HTML, CSV, and XML.

好消息是,我们可以使用jacoco:report目标,以便生成多种格式的可读代码覆盖率报告,如HTML、CSV和XML。

For example, now we can take a look at the target/site/jacoco/index.html page to see what the generated report looks like:

例如,现在我们可以看一下target/site/jacoco/index.html页面,看看生成的报告是什么样子。

coverage

Following the link provided in the report, Palindrome.java , we can drill through a more detailed view for each Java class:

按照报告中提供的链接,Palindrome.java,我们可以对每个Java类进行更详细的查看。

palindrometest1-1

Note that we can straightforwardly manage code coverage using JaCoCo inside Eclipse with zero configuration, thanks to the EclEmma Eclipse plugin.

请注意,由于EclEmma Eclipse插件的存在,我们可以在Eclipse内使用JaCoCo直接管理代码覆盖率,并且零配置

4. Report Analysis

4.报告分析

Our report shows 21% instructions coverage, 17% branches coverage, 3/5 for cyclomatic complexity, and so on.

我们的报告显示,指令覆盖率为21%,分支覆盖率为17%,循环复杂性为3/5,等等。

The 38 instructions shown by JaCoCo in the report refer to the byte code instructions, as opposed to ordinary Java code instructions.

JaCoCo在报告中显示的38条指令是指字节代码指令,而不是普通的Java代码指令。

JaCoCo reports help us visually analyze code coverage by using diamonds with colors for branches, and background colors for lines:

JaCoCo报告通过使用带有颜色的钻石表示分支,背景颜色表示行,帮助我们直观地分析代码覆盖率。

  • Red diamond means that no branches have been exercised during the test phase.
  • Yellow diamond shows that the code is partially covered – some branches have not been exercised.
  • Green diamond means that all branches have been exercised during the test.

The same color code applies to the background color, but for lines coverage.

同样的颜色代码适用于背景颜色,但对于线条覆盖。

JaCoCo mainly provides three important metrics:

JaCoCo主要提供三个重要指标。

  • Lines coverage reflects the amount of code that has been exercised based on the number of Java byte code instructions called by the tests.
  • Branches coverage shows the percent of exercised branches in the code, typically related to if/else and switch statements.
  • Cyclomatic complexity reflects the complexity of code by giving the number of paths needed to cover all the possible paths in a code through linear combination.

To take a trivial example, if there are no if or switch statements in the code, the cyclomatic complexity will be 1, as we only need one execution path to cover the entire code.

举个微不足道的例子,如果代码中没有ifswitch语句,循环复杂性将是1,因为我们只需要一条执行路径来覆盖整个代码。

Generally, the cyclomatic complexity reflects the number of test cases we need to implement in order to cover the entire code.

一般来说,循环复杂性反映了我们需要实现的测试用例的数量,以便覆盖整个代码。

5. Concept Breakdown

5.概念分解

JaCoCo runs as a Java agent. It’s responsible for instrumenting the byte code while running the tests. JaCoCo drills into each instruction, and shows which lines are exercised during each test.

JaCoCo作为一个Java代理运行。它负责在运行测试时对字节代码进行测量。JaCoCo 对每条指令进行钻研,并显示在每个测试中哪些行被锻炼了。

To gather coverage data, JaCoCo uses ASM for code instrumentation on the fly, receiving events from the JVM Tool Interface in the process:

为了收集覆盖率数据,JaCoCo使用ASM进行实时代码检测,在此过程中从JVM工具接口接收事件。

jacoco concept

It’s also possible to run the JaCoCo agent in server mode. In this case, we can run our tests with jacoco:dump as a goal in order to initiate a dump request.

也可以在服务器模式下运行JaCoCo代理。在这种情况下,我们可以将jacoco:dump作为目标来运行我们的测试,以便启动转储请求。

We can follow the official documentation link for more in-depth details about JaCoCo design.

我们可以按照官方文件链接了解更多关于JaCoCo设计的深入细节。

6. Code Coverage Score

6.代码覆盖率得分

Now that we know a bit about how JaCoCo works, let’s improve our code coverage score.

现在我们对JaCoCo的工作原理有了一些了解,让我们来提高我们的代码覆盖率得分。

In order to achieve 100% code coverage, we need to introduce tests that cover the missing parts shown in the initial report:

为了达到100%的代码覆盖率,我们需要引入测试来覆盖初始报告中显示的缺失部分。

@Test
public void whenPalindrom_thenAccept() {
    Palindrome palindromeTester = new Palindrome();
    assertTrue(palindromeTester.isPalindrome("noon"));
}
    
@Test
public void whenNearPalindrom_thanReject(){
    Palindrome palindromeTester = new Palindrome();
    assertFalse(palindromeTester.isPalindrome("neon"));
}

Now we have enough tests to cover our the entire code, but to make sure of that, let’s run the Maven command mvn jacoco:report to publish the coverage report:

现在我们有足够的测试来覆盖整个代码,但为了确保这一点,让我们运行Maven命令mvn jacoco:report来发布覆盖率报告。

coverage

As we can see, all the lines/branches/paths in our code are fully covered:

正如我们所看到的,我们的代码中所有的行/桥/路径都被完全覆盖。

coverage

In a real world project, as developments go further, we need to keep track of the code coverage score.

在现实世界的项目中,随着发展的深入,我们需要跟踪代码覆盖率的分数。

JaCoCo offers a simple way of declaring minimum requirements that should be met, otherwise the build will fail.

JaCoCo提供了一种简单的方法来声明应该满足的最低要求,否则构建将失败。

We can do that by adding the following check goal in our pom.xml file:

我们可以通过在pom.xml文件中添加以下check目标来做到这一点。

<execution>
    <id>jacoco-check</id>
    <goals>
        <goal>check</goal>
    </goals>
    <configuration>
        <rules>
            <rule>
                <element>PACKAGE</element>
                <limits>
                    <limit>
                        <counter>LINE</counter>
                        <value>COVEREDRATIO</value>
                        <minimum>0.50</minimum>
                    </limit>
                </limits>
            </rule>
        </rules>
    </configuration>
</execution>

As we can see, we’re limiting the minimum score for lines coverage to 50%.

正如我们所看到的,我们将线路覆盖率的最低得分限制在50%。

The jacoco:check goal is bound to verify, so we can run the Maven command mvn clean verify to check whether the rules are respected or not. The logs will show something like:

jacoco:check目标绑定verify,所以我们可以运行Maven命令mvn clean verify来检查规则是否被遵守。日志会显示如下内容。

[ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.7.7.201606060606:check 
  (jacoco-check) on project mutation-testing: Coverage checks have not been met.

7. Conclusion

7.结论

In this article, we learned how to make use of the JaCoCo maven plugin to generate code coverage reports for Java projects.

在这篇文章中,我们学习了如何利用JaCoCo maven插件来为Java项目生成代码覆盖率报告。

Keep in mind though, 100% code coverage doesn’t necessarily reflect effective testing, as it only reflects the amount of code exercised during tests. In a previous article, we talked about mutation testing as a more sophisticated way to track the effectiveness of tests compared to ordinary code coverage.

但请记住,100%的代码覆盖率并不一定反映有效的测试,因为它只反映了测试过程中行使的代码量。在之前的文章中,我们谈到了mutation testing,与普通的代码覆盖率相比,这是一种更复杂的跟踪测试有效性的方法。

The example provided in this article is available over in the GitHub project.

本文提供的例子可在GitHub项目中找到。