Using JUnit, JaCoCo and Maven for code coverage

JaCoCo is quite a new tool for measuring and reporting code coverage with full support for Java 7. Currently it supports instruction, branch, line, method and class coverage which is pretty anything you can expect from this kind of tool. Additionally, it can measure and report cyclomatic complexity for methods and summarize the complexity for classes and packages.

Project setup

The steps necessary to use JaCoCo are very simple. First you need to add few unit tests to an existing project if there are none. In our simple project we have following Rectangle class:

package com.example.jacoco;

public class Rectangle {
    private int x;
    private int y;
    private int width;
    private int height;
    
    public Rectangle(int x, int y, int width, int height) {
        if (width <= 0 || height <= 0)
            throw new IllegalArgumentException("Dimensions are not positive");
        
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    
    public boolean intersects(Rectangle other) {
        if (x + width <= other.x)
            return false;
        if (x >= other.x + other.width)
            return false;
        return (y + height > other.y && y < other.y + other.height);
    }
}

and few tests for this class which should cover all possible cases:

package com.example.jacoco;

import org.junit.Test;
import static org.junit.Assert.*;

public class RectangleTestCase {
    
    @Test
    public void testCorner1() {
        Rectangle rect1 = new Rectangle(0, 0, 5, 5);
        Rectangle rect2 = new Rectangle(-2, -2, 3, 3);
        assertTrue(rect1.intersects(rect2));
        assertTrue(rect2.intersects(rect1));
    }

    @Test
    public void testCorner2() {
        Rectangle rect1 = new Rectangle(0, 0, 5, 5);
        Rectangle rect2 = new Rectangle(3, -2, 4, 4);
        assertTrue(rect1.intersects(rect2));
        assertTrue(rect2.intersects(rect1));
    }

    @Test
    public void testOutside1() {
        Rectangle rect1 = new Rectangle(0, 0, 5, 5);
        Rectangle rect2 = new Rectangle(5, 5, 4, 4);
        assertFalse(rect1.intersects(rect2));
        assertFalse(rect2.intersects(rect1));
    }

    @Test
    public void testOutside2() {
        Rectangle rect1 = new Rectangle(0, 0, 5, 5);
        Rectangle rect2 = new Rectangle(3, -2, 3, 2);
        assertFalse(rect1.intersects(rect2));
        assertFalse(rect2.intersects(rect1));
    }

    @Test
    public void testInside1() {
        Rectangle rect1 = new Rectangle(0, 0, 5, 5);
        Rectangle rect2 = new Rectangle(0, 2, 2, 2);
        assertTrue(rect1.intersects(rect2));
        assertTrue(rect2.intersects(rect1));
    }

}

The next step is to add jacoco-maven-plugin to our POM:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.6.3.201306030806</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>

This will trigger the measurement of code coverage every time unit tests are run. The results will be saved by default into target/jacoco.exec binary file.

Reporting

Manually reading the binary file is almost impossible so it is better to convert it to a more user-friendly version using command:

[robert@epsilon jacoco]$ mvn jacoco:report

Once this command finishes, the report can be found in target/site/jacoco directory in three different formats (CSV, XML and HTML). The HTML version of this report looks like this:
jacoco

Analysis

The green lines represent parts of the code which were fully covered by tests. The yellow line means that given branch was not fully covered because its condition never evaluated to true. Additionally, the next line is red because this line was never executed by our tests.
Rest of the lines are white because they do not represent any instruction.

Integration with IDE

If you use IDE, it is very likely that it provides its own support for measuring and reporting code coverage.

In Eclipse you have to install EclEmma plugin first according to official instructions. Once it is done, you can measure code coverage and see the report by clicking Coverage button on the toolbar. For details please see EclEmma user guide.

In NetBeans 7.1 or later there is no need to install plugin because it is included by default. Therefore, to measure code coverage and see the report you can select Code Coverage -> Show Report from project context-menu. The details are available at official wiki.

Integration with CI server

Jenkins provides a nice plugin for JaCoCo which can publish the report on CI server site. This way everybody can monitor code coverage without actually building and testing the software on its own machine.

The plugin also lets you define the minimum allowed values for metrics. If the actual metrics are lower than configured minimum, Jenkins will report an error during build.

For details on how to configure it please see official JaCoCo plugin page.

Conclusion

The whole idea of code coverage is to measure how good our tests are. If the metrics provided by code coverage tool are high and satisfactory, there is nothing more to do. However, if they are low, we should consider writing few more tests based on the report generated by the tool.

In our case JaCoCo showed that we should still write a unit test for situation when width or height of the rectangle is not positive.

The source code for this example can be found at GitHub.

Advertisements

About Robert Piasecki

Husband and father, Java software developer, Linux and open-source fan.
This entry was posted in Code coverage, Java, Maven, Software development practices and tagged , , , , , . Bookmark the permalink.

3 Responses to Using JUnit, JaCoCo and Maven for code coverage

  1. when using eclipse, you may also want to look at eclemma

    • robertp1984 says:

      Thank you for pointing this out because without any information about integration with IDE, this post was somewhat incomplete. I have added brief instructions how to do it in Eclipse and NetBeans.

  2. Vigneswaran Rajendran says:

    Great explanation in detail. Couldnt find such content anywhere else

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s