Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Getting Started with Code Coverage by Jacoco

4.72/5 (9 votes)
24 Oct 2014CPOL6 min read 93.8K   861  
This article presents an example Maven project to get started with unit test code coverage by Jacoco.

Introduction

This article presents an example Maven project to get started with unit test code coverage by Jacoco.

Background

It is always nice to get some statistics on the code coverage by the unit tests, and Jacoco is one of the most popular code coverage frameworks. The following is the attached example Maven project shown in the project explorer in the Eclipse IDE.

Image 1

I have tested this example project in JDK-1.7.0_60, Apache Maven 3.2.1, and Eclipse Java EE IDE for Web Developers Version: Kepler Service Release 2 in a Windows computer.

The Classes to Test

For the demonstration purpose, I created the following two classes to be unit tested.

Java
package org.song.example;
    
public class Student {
    private int id;
    private String name;
    private int score;
    
    public Student(int id, String name, int score) {
        this.id = id;
        this.name = name;
        this.score = score;
    }
    
    public int getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }
    
    public int getScore() {
        return score;
    }
}
Java
package org.song.example;
    
import java.util.HashMap;
    
public class StudyGroup {
    private HashMap<Integer, Student> students;
    
    public StudyGroup() {
        students = new HashMap<Integer, Student>();
    }
    
    public void addStudent(Student student) {
        int id = student.getId();
        students.put(id, student);
    }
    
    public Student getStudent(int id) {
        return students.get(id);
    }
    
    public void removeStudent(int id) {
        students.remove(id);
    }
    
    public void clear() {
        students.clear();
    }
    
    public int getGroupSize() {
        return students.size();
    }
}

 

The Unit Test Class

The "StudyGroupTest" class is the unit test class created to test the classes "Student" and "StudyGroup".

Java
package org.song.example;
    
import java.util.ArrayList;
import java.util.List;
    
import org.testng.Assert;
import org.testng.annotations.Test;
    
public class StudyGroupTest {
    @Test
    public void testStudyGroupClass() {
        // prepare the data for test
        final List<Student> testStudents = new ArrayList<Student>();
        testStudents.add(new Student(1, "Student No.1", 60));
        testStudents.add(new Student(2, "Student No.2", 70));
        testStudents.add(new Student(3, "Student No.2", 80));
        
        // Start the unit test
        final StudyGroup testGroup = new StudyGroup();
        for(Student student: testStudents) {
            testGroup.addStudent(student);
        }
        Assert.assertEquals(testGroup.getGroupSize(), testStudents.size());
        
        Student testStudent = testStudents.get(0);
        Student returnedStudent = testGroup.getStudent(testStudent.getId());
        Assert.assertSame(returnedStudent, testStudent);
        Assert.assertEquals(returnedStudent.getId(), testStudent.getId());
        Assert.assertEquals(returnedStudent.getName(), testStudent.getName());
        Assert.assertEquals(returnedStudent.getScore(), testStudent.getScore());
        
        testGroup.removeStudent(testStudent.getId());
        Assert.assertEquals(testGroup.getGroupSize(), testStudents.size() - 1);
        
        testGroup.clear();
        Assert.assertEquals(testGroup.getGroupSize(), 0);
    }
}

 

The "pom.xml" file

The "pom.xml" file is the place where we can configure the Maven project to use Jacoco to generate the code coverage report.

XML
<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>org.song.example</groupId>
    <artifactId>jacoco-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <properties>
        <testng.version>6.8.8</testng.version>
        <java.version>1.7</java.version>
        <surefire.version>2.17</surefire.version>
        <jacoco.version>0.7.2.201409121644</jacoco.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
      
    <build>
        <finalName>${project.artifactId}</finalName>
            
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire.version}</version>
            </plugin> 
            
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                                  
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals><goal>prepare-agent</goal></goals>
                    </execution>
                    <execution>
                        <id>default-report</id>
                        <phase>prepare-package</phase>
                        <goals><goal>report</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  • Since I am using TestNG to run the unit test, the TestNG is added as a Maven dependency;
  • To use Jacoco to generate the code coverage report, we can simply add the Jacoco plugin in the "pom.xml" and give it some very simple configurations.

If you have a stand-alone Maven installed on your computer, you can simply issue the "mvn clean install" command against the "pom.xml" file and the code coverage report will be generated. But before looking into the code coverage report, let us import the Maven project into Eclipse.

Import the Maven Project into Eclipse

In theory, we do not need any IDE to work on Maven projects, but it is always nice to have an IDE. As far as I know, Eclipse supports Maven projects by default since Eclipse Java EE IDE for Web Developers Version: Kepler Service Release 2. If your Eclipse does not support Maven project, I would recommend upgrading to a newer version or install the "m2e" by yourself. Besides the Maven support, it will be nice if you also have the EclEMMA plugin installed in your Eclipse. The reason why you need the EclEMMA plugin is that "m2e" by default does not recognize the Jacoco Maven goal "prepare-agent". By installing the EclEMMA plugin, your importing of the attached Maven project will be much easier. To install the EclEMMA plugin, you can go to "Help" -> "Eclipse Marketplace ..." from the Eclipse menu and search for "EclEMMA".

Image 2

After installing EclEMMA, you can then go to "File" -> "Import ..." -> "Maven" -> "Existing Maven Projects" from the Eclipse menu to import the project. After browsing to the folder where the "pom.xml" file is located and click the "Finish" button, you should be able to successfully import the Maven project into your Eclipse workspace.

Image 3

Although it is strongly discouraged, if you do not want to install the EclEMMA plugin, you can still import the attached Maven project. You need to add the following section to the "lifecycle-mapping-metadata.xml" file for your Eclipse workspace to tell the Eclipse to ignore the Jacoco "prepare-agent" goal for all the Maven projects in the workspace.

XML
<?xml version="1.0" encoding="UTF-8"?>
<lifecycleMappingMetadata>
  <pluginExecutions>
    <pluginExecution>
      <pluginExecutionFilter>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <versionRange>0.7.2.201409121644</versionRange>
        <goals>
          <goal>prepare-agent</goal>
        </goals>
      </pluginExecutionFilter>
      <action>
        <ignore />
      </action>
    </pluginExecution>
  </pluginExecutions>
</lifecycleMappingMetadata>

You can find the location of the "lifecycle-mapping-metadata.xml" file from "Window" -> "Preferences" -> "Maven" -> "Lifecycle Mappings" from the Eclipse menu.

Image 4

Run the Maven Build and View the Coverage Reports

You have two ways to build the Maven project. In Eclipse, you can right click the "pom.xml" file and run the Maven build. If you have a stand-alone Maven installation on your computer, you can also issue the "mvn clean install" command directly against the "pom.xml" using your stand-alone Maven. Upon a successful Maven build, the code coverage report is ready in the "target\site\jacoco" folder in your Maven project.

Image 5

If you open the "index.html" file in a browser, you can start to look at the code coverage report.

Image 6

You can then follow the hyper-links to see the details of the report.

Image 7

You can even look into the files to see the lines that are covered or not covered by the unit tests.

Image 8

Code Coverage != Software Quality

In the software world, we have heard the unit test and code coverage many times again and again. It is a good idea to emphasize the importance of code coverage, but we should also realize that code coverage itself does not necessarily mean high quality. If we take a look at the attached Maven project, we have a good reason to be happy because we achieved 100% code coverage. But let us take a further look at the following method in the "StudyGroup" class.

Java
public void addStudent(Student student) {
        int id = student.getId();
        students.put(id, student);

}

We should have noticed that if a "null" student is passed in to the method, we will immediately encounter a run-time exception, although we have a 100% code coverage. I strongly believe that the quality of the software is the combined effort on many things. I believe that a clearly defined feature set, a well designed software architecture, a well selected data structure and algorithm set, and a set of well selected test cases are the fundamental building blocks of a high quality software product. I also believe that the high quality software engineers who think about every possibilities before putting down every single line of code responsibly are the important part of the quality, even more important than how we test the product. In any case, the code coverage report and the frameworks like Jacoco should find their places in a high quality software product.

Points of Interest

  • This article presented an example Maven project to get started with unit test code coverage by Jacoco;
  • It also discussed some issues to import Maven projects that have Jacoco support into Eclipse and how to address these issues;
  • The EclEMMA plugin discussed in this article is a very nice tool to check code coverage in the Eclipse IDE. I did not talk about how to use it in the Eclipse IDE, because it is very intuitive and very easy to use. It is a very important boost of the productivity beyond the Jacoco Maven plugin;
  • The code coverage itself is not a guarantee of the quality of the software. We need to target the product quality at the very beginning of the development phase and we need to pay a lot more attention on how to design our test cases to achieve the best quality in our work;
  • Besides Jacoco, Cobertura is another popular code coverage tool for Java programs. If you are interested, you may take a look at Cobertura. In my recent experience, I noticed that I could not install the Cobertura Eclipse plugin because it no longer supports the newer versions of Eclipse. I hope the problem can be solved sooner and we can keep enjoying Cobertura.
  • I hope you like my postings and I hope this article can help you one way or the other.

History

First Revison - 10/24/2014.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)