JUnit Code Coverage

JaCoCo is quite a new maven plug-in that provides the JaCoCo runtime agent to your tests and allows basic report creation. Currently it supports instruction, branch, line, method and class coverage which is pretty enough 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.

So if you want to have line number information included in the coverage reports or you want source code highlighting the class files of the test target must be compiled with debug information.

Note when it is used in conjuction with the maven-surefire-plugin or maven-failsafe-plugin you must not use a forkCount of 0 or set the forkMode to never as this would prevent the execution of the tests with the javaagent set and no coverage would be recorded.

What is branch coverage

Decision Coverage is also known as Branch Coverage or all-edges coverage. It covers both the true and false conditions unlikely the statement coverage. A branch is the outcome of a decision, so branch coverage simply measures which decision outcomes have been tested. For example, with the loop control statement like while or for or if statement the outcome is either true or false and the decision coverage ensures that each outcome(i.e true and false) of control statement has been executed at least once.

Example

Create a standalone maven project with artifact-id junit and group-id com.roytuts in Eclipse.

Modify the pom.xml file as shown below

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.roytuts</groupId>
    <artifactId>junit</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>junit</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
        <junit.version>4.12</junit.version>
        <jacoco.version>0.7.7.201606060606</jacoco.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <!-- JaCoCo plugin -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</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>
        </plugins>
    </build>
</project>

Create a Calculation class with the below source code under src/main/java directory

package com.roytuts.jacoco;

public class Calculation {

    public int findMax(int arr[]) {
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i])
                max = arr[i];
        }
        return max;
    }

    public int getRemainder(int dividend, int divisor) {
        if (divisor <= 0) {
            throw new IllegalArgumentException("Divisor should be greater than 0");
        }
        return dividend % divisor;
    }

}

Create a JUnit CalculationTest class with the below source code under src/test/java directory

package com.roytuts.jacoco;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

public class CalculationTest {

    private Calculation calc;

    @Before
    public void setup() {
        calc = new Calculation();
    }

    @Test
    public void testFindMax() {
        int result = calc.findMax(new int[] { 1, 3, 4, 2 });
        assertEquals(4, result);
        result = calc.findMax(new int[] { -12, -1, -3, -4, -2 });
        assertEquals(-1, result);
    }

    @Test
    public void testGetRemainder() {
        int result = calc.getRemainder(5, 2);
        assertEquals(1, result);
    }

}

Now run the above test class in Eclipse, you should see the below output.

junit code coverage

Now run the test using “mvn test” command from command prompt.

JaCoCo plugin will trigger the measurement of code coverage every time unit tests are run using “mvn test”. The results will be saved by default into target/jacoco.exec binary file.

Manually reading the binary file is almost impossible so it is better to convert it to a more user-friendly version using command “mvn jacoco:report”.

Now you will find the report has been generated in html, csv and xml formats under target directory in site/jacoco.

If you do double-click on the index.html file, you will below output (for details output you can go further inside the com.roytuts.jacoco directory). Here you will find the missed coverage.


junit code coverage

Now click on com.roytuts.jacoco under header Element. Here you will also find the method for which missed coverage occurred.


junit code coverage

Now click on any one of the Element. Here you will find the more details of the code coverage using test cases.


junit code coverage

The green lines represent the full coverage with the parts of the code. The yellow line represents missing coverage because the line was never evaluated by the code. And the red line represent because this line was never executed by the test cases.

Therefore we will bridge the gap of the test coverage by changing the testGetRemainder() method.

So make the method looks like below

@Test(expected = IllegalArgumentException.class)
public void testGetRemainder() {
	int result = calc.getRemainder(5, 2);
	assertEquals(1, result);
	calc.getRemainder(5, 0);
}

In the above method I have put “expected=IllegalArgumentException” because I know this exception is expected and I do not want the method throws the expected exception to mark test case failure.

Now execute the Junit test from Eclipse


junit code coverage

Now again execute commands “mvn test” and “mvn jacoco:report” and check the html report again.

junit code coverage

Thanks for reading.

Soumitra Roy Sarkar

I am a professional Web developer, Enterprise Application developer, Software Engineer and Blogger. Connect me on Roy Tutorials Twitter Facebook  Google Plus Linkedin Or Email Me

Leave a Reply

Your email address will not be published. Required fields are marked *