I have comfort of inspecting code with Sonar at work. Our configuration manager had installed it some time ago. Recently I wondered unit test coverage of a sample project at home (over my tablet!). I installed SonarQube, it's easy, but I was surprised by the fact that code coverage is not a native feature of it. I integrated JaCoCo Java Code Coverage Library with Maven, and let SonarQube be aware of reports generated by JaCoCo.
It took a bit more than I expected, so I share my experience here. You can also find sample project described in this article on GitHub.
1. Prerequisites
Please ensure that Java and Maven installed and JAVA_HOME is set. Please be aware that SonarQube requires Java 8 onwards$ java -version java version "1.8.0_102" ... $ mvn -version Apache Maven 3.3.9 $ echo $JAVA_HOME /path-to-java/jdk1.8.0_92
2. We need a project to work on
Lets create one using maven quickstart archetype. Archetypes are Maven project templates.
$ mvn archetype:generate -DgroupId=net.anatoly.sample.coverage -DartifactId=sample-test-coverage -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false [INFO] Scanning for projects... Downloading: [SHITLOAD of POMS and JARS] [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building Maven Stub Project (No POM) 1 [INFO] ------------------------------------------------------------------------ [INFO] [INFO] >>> maven-archetype-plugin:2.4:generate (default-cli) > generate-sources @ standalone-pom >>> [INFO] [INFO] <<< maven-archetype-plugin:2.4:generate (default-cli) < generate-sources @ standalone-pom <<< [INFO] [INFO] --- maven-archetype-plugin:2.4:generate (default-cli) @ standalone-pom --- Downloading: [SHITLOAD of POMS and JARS] [INFO] ---------------------------------------------------------------------------- [INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-quickstart:1.0 [INFO] ---------------------------------------------------------------------------- [INFO] Parameter: basedir, Value: prj\sonar-coverage\initial [INFO] Parameter: package, Value: net.anatoly.sample.coverage [INFO] Parameter: groupId, Value: net.anatoly.sample.coverage [INFO] Parameter: artifactId, Value: sample-test-coverage [INFO] Parameter: packageName, Value: net.anatoly.sample.coverage [INFO] Parameter: version, Value: 1.0-SNAPSHOT [INFO] project created from Old (1.x) Archetype in dir: prj\sonar-coverage\initial\sample-test-coverage [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 43.636 s [INFO] Finished at: 2016-12-06T19:37:44+02:00 [INFO] Final Memory: 14M/130M [INFO] ------------------------------------------------------------------------
Now we have a minimal java maven project with java source and test folders and maven pom file.
Lets test our sample project
$ mvn test [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building sample-test-coverage 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ Downloading: [SHITLOAD of POMS and JARS] [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample-test-coverage --- Downloading: [SHITLOAD of POMS and JARS] [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory prj\sonar-coverage\sonar\sample-test-coverage\src\main\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample-test-coverage --- Downloading: [SHITLOAD of POMS and JARS] [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent! [INFO] Compiling 1 source file to prj\sonar-coverage\sonar\sample-test-coverage\target\classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ sample-test-coverage --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory prj\sonar-coverage\sonar\sample-test-coverage\src\test\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sample-test-coverage --- [INFO] Changes detected - recompiling the module! [WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent! [INFO] Compiling 1 source file to prj\sonar-coverage\sonar\sample-test-coverage\target\test-classes [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ sample-test-coverage --- Downloading: [SHITLOAD of POMS and JARS] [INFO] Surefire report directory: prj\sonar-coverage\sonar\sample-test-coverage\target\surefire-reports Downloading: [SHITLOAD of POMS and JARS] ------------------------------------------------------- T E S T S ------------------------------------------------------- Running net.anatoly.sample.coverage.AppTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.006 sec Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 20.200 s [INFO] Finished at: 2016-12-06T19:58:01+02:00 [INFO] Final Memory: 17M/142M [INFO] ------------------------------------------------------------------------
Yay! It works.
But it gives encoding warnings, lets set our source encoding to UTF-8. Add below xml snippet to project pom.xml file
UTF-8
As in our example:
4.0.0
net.anatoly.sample.coverage
sample-test-coverage
jar
1.0-SNAPSHOT
sample-test-coverage
http://maven.apache.org
junit
junit
3.8.1
test
UTF-8
Encoding warnings are gone!
Now we have a sample project.
3. Install SonarQube
Installing SonarQube is easy. Just download, uncompress and run. You can follow the instructions on Sonar - Get Started in Two Minutes.
You can test the server on http://localhost:9000 and initial admin credentials are admin / admin
4. Integrate Maven with Sonar
Linked article above shows analyzing source code by console scanner. Lets integrate it with maven.
Edit the settings.xml file, located in $MAVEN_HOME/conf or ~/.m2, to set the plugin prefix and optionally the SonarQube server URL.
org.sonarsource.scanner.maven
sonar
true
http://localhost:9000
And update project pom file properties as
UTF-8
java
Now lets check if it works:
$ mvn sonar:sonar [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building sample-test-coverage 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- sonar-maven-plugin:3.2:sonar (default-cli) @ sample-test-coverage --- [unneeded details for this article] [INFO] Analysis report generated in 134ms, dir size=19 KB [INFO] Analysis reports compressed in 25ms, zip size=9 KB [INFO] Analysis report uploaded in 31ms [INFO] ANALYSIS SUCCESSFUL, you can browse http://localhost:9000/dashboard/index/net.anatoly.sample.coverage:sample-test-coverage [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=AVjVgWSwUIL7exiiY2o8 [INFO] Task total time: 5.402 s [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 10.147 s [INFO] Finished at: 2016-12-06T20:59:36+02:00 [INFO] Final Memory: 24M/227M [INFO] ------------------------------------------------------------------------
Generated report can be seen on http://localhost:9000

5 Integrate JaCoCo with Maven
Update pom.xml with below xml snippets
UTF-8
java
target/coverage-reports/jacoco-ut.exec
org.apache.maven.plugins
maven-surefire-plugin
2.15
${surefireArgLine}
${skip.unit.tests}
**/IT*.java
org.jacoco
jacoco-maven-plugin
0.7.7.201606060606
pre-unit-test
prepare-agent
${project.build.directory}/coverage-reports/jacoco-ut.exec
surefireArgLine
post-unit-test
test
report
${project.build.directory}/coverage-reports/jacoco-ut.exec
${project.reporting.outputDirectory}/jacoco-ut
Thanks to Petri Kainulainen for this part.
Now when we test our project, code coverage reports will also be generated. Nice!
$ mvn clean test [INFO] Scanning for projects... [INFO] [INFO] ------------------------------------------------------------------------ [INFO] Building sample-test-coverage 1.0-SNAPSHOT [INFO] ------------------------------------------------------------------------ [INFO] [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ sample-test-coverage --- [INFO] Deleting prj\sonar-coverage\jacoco\sample-test-coverage\target [INFO] [INFO] --- jacoco-maven-plugin:0.7.7.201606060606:prepare-agent (pre-unit-test) @ sample-test-coverage --- [INFO] surefireArgLine set to "-javaagent:\\.m2\\repository\\org\\jacoco\\org.jacoco.agent\\0.7.7.201606060606\\org.jacoco.agent-0.7.7.201606060606-runtime.jar=destfile=prj\\sonar-coverage\\jacoco\\sample-test-coverage\\target\\coverage-reports\\jacoco-ut.exec" [INFO] [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ sample-test-coverage --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory prj\sonar-coverage\jacoco\sample-test-coverage\src\main\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ sample-test-coverage --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to prj\sonar-coverage\jacoco\sample-test-coverage\target\classes [INFO] [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ sample-test-coverage --- [INFO] Using 'UTF-8' encoding to copy filtered resources. [INFO] skip non existing resourceDirectory prj\sonar-coverage\jacoco\sample-test-coverage\src\test\resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ sample-test-coverage --- [INFO] Changes detected - recompiling the module! [INFO] Compiling 1 source file to prj\sonar-coverage\jacoco\sample-test-coverage\target\test-classes [INFO] [INFO] --- maven-surefire-plugin:2.15:test (default-test) @ sample-test-coverage --- [INFO] Surefire report directory: prj\sonar-coverage\jacoco\sample-test-coverage\target\surefire-reports ------------------------------------------------------- T E S T S ------------------------------------------------------- Running net.anatoly.sample.coverage.AppTest Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.03 sec - in net.anatoly.sample.coverage.AppTest Results : Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] --- jacoco-maven-plugin:0.7.7.201606060606:report (post-unit-test) @ sample-test-coverage --- [INFO] Loading execution data file prj\sonar-coverage\jacoco\sample-test-coverage\target\coverage-reports\jacoco-ut.exec [INFO] Analyzed bundle 'sample-test-coverage' with 1 classes [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4.512 s [INFO] Finished at: 2016-12-06T21:46:41+02:00 [INFO] Final Memory: 18M/140M [INFO] ------------------------------------------------------------------------
6. Mission Complete
$ mvn sonar:sonar
And lets check on the server now!

Finally we have code coverage section on our report page. In case you missed any step you can check initial and final project files on GitHub. Please note that -Step 4- requires editing maven settings.xml which is outside the project folder.