Test Coverage analysis (with JaCoCo and Sonar) for your Spring Boot app

Test Coverage analysis (with JaCoCo and Sonar) for your Spring Boot app

One of the main metrics for a software project is Test Coverage: if done properly, it gives you a quick picture of how much code is protected by tests.

In this article, I’ll show you how to use a minimal configuration to include JaCoCo in your Spring Boot application, and how to process this information with Sonar.

Why JaCoCo?

The JaCoCo library is one of most extended solutions for measuring coverage. If you want to explore some other options you can check out this comparison by Atlassian of code coverage tools (warning: may be biased, they sell one of the options, Clover). I’ve chosen JaCoCo since it’s free and really quick to set up if you know how (and you will after reading this guide :)).

Maven configuration

Basically, you need to include some extra configuration in your pom.xml file and then, every time you execute the maven test phase, the JaCoCo plugin will generate the surefire reports.

To achieve that, you need to configure the JaCoCo plugin in your pom.xml file (check maven repository for the latest stable version):

<!-- JaCoCo configuration -->
<build>
    <plugins>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.0</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>
</builds>
This pom.xml file is part of a project available on GitHub: Code Quality Game. If you find it useful, please give it a star!

Running the plugin

With this simple configuration, you already have all you need to execute test coverage. Next time you execute maven with a goal that includes the test phase, JaCoCo will generate the reports for you. For instance, if you execute:

mvn clean test

You’ll see in the output a message like this:

[INFO] ------------------------------------------------------------------------
[INFO] Building code-quality-game 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.6.1:clean (default-clean) @ code-quality-game ---
[INFO] Deleting /Users/moises/dev/ws-blog/code-quality-game/sonar-connector/target
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.0:prepare-agent (default-prepare-agent) @ code-quality-game ---
[INFO] argLine set to -javaagent:/Users/moises/.m2/repository/org/jacoco/org.jacoco.agent/0.8.0/org.jacoco.agent-0.8.0-runtime.jar=destfile=/Users/moises/dev/ws-blog/code-quality-game/sonar-connector/target/jacoco.exec

As you can see a new file is being generated in the target directory.  This file format is not really useful for a human but it can be sent to Sonar for further analysis, or processed by several different tools (including IDEs) to show detailed reports. In the next section, we see how to connect this jacoco.exec file with SonarQube.

Sending the report to Sonar

SonarQube has a really good integration with test code coverage. It allows you to analyze which parts of the code should be better covered, and you can correlate this with many other stats. If you want to send your report to your Sonar server the only thing you need to do is execute:

mvn sonar:sonar

This command will try to reach Sonar at localhost if you don’t have an explicit configuration in your pom.xml file. If you want to connect with a different host you can also do it from the command line. For example, this command sends the JaCoCo output to a Sonar Docker image running on a VirtualBox:

mvn sonar:sonar -Dsonar.host.url=http://192.168.99.100:9000
Get the book Practical Software Architecture

This is how your command output will look like. The Sonar sensors will detect JaCoCo output and will process it:

sonar-connector master % < $ mvn sonar:sonar
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building code-quality-game 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- sonar-maven-plugin:3.4.0.905:sonar (default-cli) @ code-quality-game ---
[INFO] User cache: C:\Users\moise\.sonar\cache
[INFO] SonarQube version: 6.7.1
[INFO] Default locale: "es_ES", source code encoding: "UTF-8"
[INFO] Publish mode
[INFO] Load global settings
[INFO] Load global settings (done) | time=158ms
[INFO] Server id: AWEAdA2oL80mwIycFOL1
[INFO] User cache: C:\Users\moise\.sonar\cache
[INFO] Load plugins index
[INFO] Load plugins index (done) | time=88ms
[INFO] Process project properties
[INFO] Load project repositories
[INFO] Load project repositories (done) | time=241ms
[INFO] Load quality profiles
[INFO] Load quality profiles (done) | time=91ms
[INFO] Load active rules
[INFO] Load active rules (done) | time=2164ms
[INFO] Load metrics repository
[INFO] Load metrics repository (done) | time=89ms
[INFO] Project key: es.macero.cqgame:code-quality-game
[INFO] -------------  Scan code-quality-game
[INFO] Load server rules
[INFO] Load server rules (done) | time=1003ms
[INFO] Base dir: D:\dev\ws-blog\code-quality-game\sonar-connector
[INFO] Working dir: D:\dev\ws-blog\code-quality-game\sonar-connector\target\sonar
[INFO] Source paths: pom.xml, src/main/java
[INFO] Test paths: src/test/java
[INFO] Source encoding: UTF-8, default locale: es_ES
[INFO] Index files
[INFO] Excluded sources:
[INFO]   **/resultbeans/*.java
[INFO] 37 files indexed
[INFO] 5 files ignored because of inclusion/exclusion patterns
[INFO] Quality profile for java: Sonar way
[INFO] Quality profile for xml: Sonar way
[INFO] Sensor JavaSquidSensor [java]
[INFO] Configured Java source version (sonar.java.source): 8
[INFO] JavaClasspath initialization
[INFO] JavaClasspath initialization (done) | time=18ms
[INFO] JavaTestClasspath initialization
[INFO] JavaTestClasspath initialization (done) | time=6ms
[INFO] Java Main Files AST scan
[INFO] 30 source files to be analyzed
[INFO] Java Main Files AST scan (done) | time=2939ms
[INFO] 30/30 source files have been analyzed
[INFO] Java Test Files AST scan
[INFO] 6 source files to be analyzed
[INFO] 6/6 source files have been analyzed
[INFO] Java Test Files AST scan (done) | time=370ms
[INFO] Sensor JavaSquidSensor [java] (done) | time=5044ms
[INFO] Sensor SurefireSensor [java]
[INFO] parsing [D:\dev\ws-blog\code-quality-game\sonar-connector\target\surefire-reports]
[INFO] Sensor SurefireSensor [java] (done) | time=3ms
[INFO] Sensor JaCoCoSensor [java]
[INFO] Sensor JaCoCoSensor [java] (done) | time=2ms
[INFO] Sensor SonarJavaXmlFileSensor [java]
[INFO] 1 source files to be analyzed
[INFO] Sensor SonarJavaXmlFileSensor [java] (done) | time=486ms
[INFO] 1/1 source files have been analyzed
[INFO] Sensor XML Sensor [xml]
[INFO] Sensor XML Sensor [xml] (done) | time=178ms
[INFO] Sensor Analyzer for "php.ini" files [php]
[INFO] Sensor Analyzer for "php.ini" files [php] (done) | time=4ms
[INFO] Sensor Zero Coverage Sensor
[INFO] Sensor Zero Coverage Sensor (done) | time=36ms
[INFO] Sensor CPD Block Indexer
[INFO] Sensor CPD Block Indexer (done) | time=44ms
[INFO] SCM provider for this project is: git
[INFO] 1 files to be analyzed
[INFO] 1/1 files analyzed
[INFO] 10 files had no CPD blocks
[INFO] Calculating CPD for 20 files
[INFO] CPD calculation finished
[INFO] Analysis report generated in 1217ms, dir size=190 KB
[INFO] Analysis reports compressed in 106ms, zip size=101 KB
[INFO] Analysis report uploaded in 131ms
[INFO] ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/es.macero.cqgame:code-quality-game
[INFO] Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
[INFO] More about the report processing at http://localhost:9000/api/ce/task?id=AWEcc-IyZ9wNhwVcsvFP
[INFO] Task total time: 13.827 s
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 18.968 s
[INFO] Finished at: 2018-01-22T07:00:12+01:00
[INFO] Final Memory: 33M/482M
[INFO] ------------------------------------------------------------------------

That’s all. Now you can go to the Sonar Web interface and check your code coverage there. You will see not covered pieces of code with messages like the one shown in the screenshot below: ‘Not covered by Unit Tests’.

If you want to try this, or have questions about parts of the configuration, there is a sample project available on GitHub: Code Quality Game. It contains a docker-compose.yml file, so you can run SonarQube in a Docker container and see the coverage results. If you find it useful, please give it a star!

If you want to know more:

sonar coverage

Moisés Macero's Picture

About Moisés Macero

Software Developer, Architect, and Author.
Do you need help?

Amsterdam, The Netherlands https://thepracticaldeveloper.com