
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>
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

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’.
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:
- Check my Complete Guide to REST (Controller) Tests in Spring Boot: Unit and Integration Tests
- Visit A Gamification experiment with Sonarqube if you're interested in knowing more about the sample project
- Buy my book to get real experience with Spring Boot applications and proper Testing.
Comments