JMS integration tests with Maven and Glassfish - maven

I'm developing an app requiring MDB, running over Glassfish 3.1. I've managed already to run unit/integration tests of simple EJBs using embedded container with no problem. Now I'm trying to create integration tests for my MDBs.
1) I tried launching the Glassfish embedded server programatically, but it does not support creation of JMS queues.
2) I run a Glassfish server from the Maven plugin.
Now I can create queues, and deploy my MDBs, no problem at all. Now, I just can't figure out a way of running JUnit.
- When I create an InitialContext, it times-out when accessing the local server. I have no ways of accessing my beans.
I found a workaround, but it's not serving my needs perfectly:
In my test sources, I created a simple Singleton #Startup bean. In the #PostConstruct method, I call the unit test classes I want to achieve. In order for this bean to be deployed, I have a special special maven build rule that packages some of my tests files in the EJB jar. Deploying this special jar results in my tests being launch. To make it clear, here's an extract of my Maven file:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<phase>pre-integration-test</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/test-ejb</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}/classes</directory>
</resource>
<resource>
<directory>${project.build.directory}/test-classes</directory>
<includes>
<include>**/*TestTrigger.class</include>
<include>**/*IntegrationTest.class</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.3</version>
<configuration>
<ejbVersion>3.1</ejbVersion>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>ejb</goal>
</goals>
<configuration>
<classifier>TEST</classifier>
<outputDirectory>${project.build.directory}/test-ejb</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.glassfish</groupId>
<artifactId>maven-embedded-glassfish-plugin</artifactId>
<version>${glassfish.version}</version>
<configuration>
<goalPrefix>glassfish</goalPrefix>
<app>target/${project.build.finalName}-TEST.jar</app>
<port>8080</port>
<name>MyApp</name>
<serverID>embedded</serverID>
</configuration>
<executions>
<execution>
<id>start</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>admin</id>
<phase>pre-integration-test</phase>
<goals>
<goal>admin</goal>
</goals>
<configuration>
<commands>
<param>create-jms-resource --restype javax.jms.QueueConnectionFactory jms/TestQueueConnectionFactory</param>
<param>create-jms-resource --restype javax.jms.Queue --property imqDestinationName=ceQueue jms/ceQueue</param>
</commands>
</configuration>
</execution>
<execution>
<id>deploy</id>
<phase>pre-integration-test</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
<execution>
<id>stop</id>
<phase>post-integration-test</phase>
<goals>
<goal>undeploy</goal>
<goal>stop</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
Now, is there any way my IntegrationTest can be launched using surfire, in order to produce a proper report and fail build if test don't pass? Not to mention Cobertura.
Thank you for your help.

I didn't solve my problem so to say. What I had to do is upgrade to GlassFish 3.1.1. This version supports JMS in embedded mode. Therefore I can run a server programatically and deploy the queues I want using the admin command runner.
I just lost a bit of time trying to name my connection factory jms/connectionFactory where the jms/ prefix was unnecessary and was failing all lookups.
I also had to include a thread sleep in all my unit tests or else the server would close before tests are over.

Related

Integration tests create files for the packaged jar

I'm generating spring-restdocs snippets with rest assured in my integration tests.
With maven and the failsafe plugin that defaults to the integration-test and verify phase. Problem is, that asciidoctor-maven-plugin (to generate the final HTML file out of the snippets) and maven-resources-plugin (to copy the final HTML file into the correct place) run before the integration tests in prepare-package.
With that asciidoctor naturally fails, because the snippets are not generated yet.
If I configure asciidoctor to run at post-integration-test, it succeeds, but then the finished HTML page is not in my jar, cause the jar was already created in the package phase.
So I feel like the only option is to run my integration tests already in the tests phase (probably with surefire instead of failsafe).
I could also split out the Documentation related tests from the rest of the integration tests, but I actually like to have them in the seemingly correct place.
I wonder if there is a best practice I'm ignoring?
Should integration tests never produce something to put inside the jar?
It looks to me, that integration tests in maven are meant for cross-jar tests (hence running them after package). And not like I'm using them, just for bigger tests that involve multiple parts (especially DB) all within one jar.
What I would like:
run all tests
compile documentation
package everything into the jar
Excerpt from my pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<skip>${skipSurefire}</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>**/*IT.java</include>
<include>**/*E2ET.java</include>
</includes>
</configuration>
</plugin>
<!-- Compile API documentation -->
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.8</version>
<executions>
<execution>
<id>generate-docs</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html</backend>
<doctype>book</doctype>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-asciidoctor</artifactId>
<version>${spring-restdocs.version}</version>
</dependency>
</dependencies>
</plugin>
<!-- Package API documentation -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.outputDirectory}/public/docs
</outputDirectory>
<resources>
<resource>
<directory>
${project.build.directory}/generated-docs
</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
The phases integration-test and verify are just the default bindings of the integration-test and the verify goal. You can bind your integration tests to the test phase, as well:
...
<artifactId>maven-failsafe-plugin</artifactId>
...
<executions>
<execution>
<id>integration-tests</id>
<phase>test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
and such achieve the order you like/need.

Springboot failsafe multi-module integration test

I have to run integration-test with fail safe and my project is a multi module project, with one module for selenium test and another one with the actual web app.
I want to run the web app then the test over this app and then stopping this app and getting the report of the integration tests.
In order to do this I used this, inside the pom of the selenium test module :
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>reserve-tomcat-port</id>
<goals>
<goal>reserve-network-port</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<portNames>
<portName>tomcat.http.port</portName>
</portNames>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.9.RELEASE</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<includes>
<include>
<groupId>com.example</groupId>
<artifactId>web-app</artifactId>
</include>
</includes>
<mainClass>com.example.App</mainClass>
<arguments>
<argument>--server.port=${tomcat.http.port}</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<test.server.port>${tomcat.http.port}</test.server.port>
</systemPropertyVariables>
</configuration>
</plugin>
The error I get is that the main class is not found :
java.lang.ClassNotFoundException: App
It feels like inside the selenium test I can't get to the webapp classPath, It seems like its trying to run the selenium test main instead of the webapp's one

Command line mvn parameter to stop spring-boot-maven-plugin from executing run

I'm developing a Spring Boot application and as part of the Integration Test phase of my maven project, I have configured the spring-boot maven plugin to start up and shut down during the pre and post integration test parts of the build as follows:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
However, I did this just so that my developers can run their tests against a local instance of the service. On Jenkins, I would run the tests against an external service where I had deployed the service and I do not need the Spring Boot application to be spun up within the Jenkins job.
Is there a way for me to explicitly stop the spring-boot maven plugin from starting up the service via a mvn command line override?
Sure, you can expose a property for it, something like
<properties>
<skip.it>false</skip.it>
</properties>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</execution>
</executions>
</plugin>
Once you have that, run your command as follows: mvn verify -Dskip.it=true and the Spring Boot application will not be started as part of your integration tests.

How to run junit tests when jetty is configured to start/end at pre/post-integration-test?

I want to run junit tests, while jetty is running , how to correctly configure this?
Now it seems that the tests run before jetty is started so they can't get a connection and the project build fails.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.7.1</version>
<executions>
<execution>
<id>integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<phase>verify</phase>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.10.v20130312</version>
<configuration>
<connectors>
<connector implementation="org.eclipse.jetty.server.bio.SocketConnector">
<port>9090</port>
<maxIdleTime>60000</maxIdleTime>
</connector>
</connectors>
<scanIntervalSeconds>10</scanIntervalSeconds>
<stopKey>foo</stopKey>
<stopPort>9999</stopPort>
<jvmArgs>-Xms1024m -Xmx2048m</jvmArgs>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
<configuration>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit4</artifactId>
<version>2.16</version>
</dependency>
</dependencies>
</plugin>
Please help me with this! How to ensure that the junit tests (during the maven build) run in the integration-phase?
The Maven test phase is for running 'Unit' tests, that is, small tests that check that the smallest possible functionality or 'Unit' is functioning as expected.
These are run by the Maven Surefire plugin. You can find more info on this here:
http://maven.apache.org/surefire/maven-surefire-plugin/
What you have are integration tests. That is, they are broader tests that check that different parts of your code integrates together. This is run by the Maven Failsafe plugin which you can find more details on here:
http://maven.apache.org/surefire/maven-failsafe-plugin/
What you need to do is identify your integration tests as integration tests to the Failsafe plugin. By default, it picks up classes named **/IT*.java, **/*IT.java, and **/*ITCase.java. The naming conventions between the plugins is mutually exclusive by default so your tests should only run in one or the other.
If you only have integration tests then you can configure Surefire to run during the integration-test phase instead. Instructions on doing that here:
http://docs.codehaus.org/pages/viewpage.action?pageId=62120

How to configure multi-module Maven + Sonar + JaCoCo to give merged coverage report?

I've searched up and down the internet for this one. There's lots of half-answers out there, to do with Maven properties such as ${sonar.jacoco.reportPath}, or org.jacoco:jacoco-maven-plugin:prepare-agent or setting maven-surefire-plugin argLine with -javaagent.
Some how, none of these answers, either on their own, or in combination, are producing what I'm after:
A coverage report which shows a class as covered if it is used in tests higher up the stack, such as entities being used by DAOs, even though it was not fully covered by tests in its own module.
Is there a definitive config somewhere, to achieve this, please?
I was in the same situation as you, the half answers scattered throughout the Internet were quite annoying, since it seemed that many people had the same issue, but no one could be bothered to fully explain how they solved it.
The Sonar docs refer to a GitHub project with examples that are helpful. What I did to solve this was to apply the integration tests logic to regular unit tests (although proper unit tests should be submodule specific, this isn't always the case).
In the parent pom.xml, add these properties:
<properties>
<!-- Sonar -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
</properties>
This will make Sonar pick up unit testing reports for all submodules in the same place (a target folder in the parent project). It also tells Sonar to reuse reports ran manually instead of rolling its own. We just need to make jacoco-maven-plugin run for all submodules by placing this in the parent pom, inside build/plugins:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.6.0.201210061924</version>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
destFile places the report file in the place where Sonar will look for it and append makes it append to the file rather than overwriting it. This will combine all JaCoCo reports for all submodules in the same file.
Sonar will look at that file for each submodule, since that's what we pointed him at above, giving us combined unit testing results for multi module files in Sonar.
NEW WAY SINCE VERSION 0.7.7
Since Version 0.7.7 there is a new way to create an aggregated report:
You create a separate 'report' project which collects all the necessary reports (Any goal in the aggregator project is executed before its modules therefore it can't be used).
aggregator pom
|- parent pom
|- module a
|- module b
|- report module
The root pom looks like this (don't forget to add the new report module under modules):
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
The poms from each sub module doesn't need to be changed at all. The pom from the report module looks like this:
<!-- Add all sub modules as dependencies here -->
<dependencies>
<dependency>
<module a>
</dependency>
<dependency>
<module b>
</dependency>
...
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
<executions>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
A full exmple can be found here.
FAQ
Questions from the top of my head since that time I gone crazy with jacoco.
My application server (jBoss, Glassfish..) located in Iraq, Syria, whatever.. Is it possible to get multi-module coverage when running integration tests on it? Jenkins and Sonar are also on different servers.
Yes. You have to use jacoco agent that runs in mode output=tcpserver, jacoco ant lib. Basically two jars. This will give you 99% success.
How does jacoco agent works?
You append a string
-javaagent:[your_path]/jacocoagent.jar=destfile=/jacoco.exec,output=tcpserver,address=*
to your application server JAVA_OPTS and restart it. In this string only [your_path] have to be replaced with the path to jacocoagent.jar, stored(store it!) on your VM where app server runs. Since that time you start app server, all applications that are deployed will be dynamically monitored and their activity (meaning code usage) will be ready for you to get in jacocos .exec format by tcl request.
Could I reset jacoco agent to start collecting execution data only since the time my test start?
Yes, for that purpose you need jacocoant.jar and ant build script located in your jenkins workspace.
So basically what I need from http://www.eclemma.org/jacoco/ is jacocoant.jar located in my jenkins workspace, and jacocoagent.jar located on my app server VM?
That's right.
I don't want to use ant, I've heard that jacoco maven plugin can do all the things too.
That's not right, jacoco maven plugin can collect unit test data and some integration tests data(see Arquillian Jacoco), but if you have for example rest assured tests as a separated build in jenkins, and want to show multi-module coverage, I can't see how maven plugin can help you.
What exactly does jacoco agent produce?
Only coverage data in .exec format. Sonar then can read it.
Does jacoco need to know where my java classes located are?
No, sonar does, but not jacoco. When you do mvn sonar:sonar path to classes comes into play.
So what about the ant script?
It has to be presented in your jenkins workspace. Mine ant script, I called it jacoco.xml looks like that:
<project name="Jacoco library to collect code coverage remotely" xmlns:jacoco="antlib:org.jacoco.ant">
<property name="jacoco.port" value="6300"/>
<property name="jacocoReportFile" location="${workspace}/it-jacoco.exec"/>
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
<classpath path="${workspace}/tools/jacoco/jacocoant.jar"/>
</taskdef>
<target name="jacocoReport">
<jacoco:dump address="${jacoco.host}" port="${jacoco.port}" dump="true" reset="true" destfile="${jacocoReportFile}" append="false"/>
</target>
<target name="jacocoReset">
<jacoco:dump address="${jacoco.host}" port="${jacoco.port}" reset="true" destfile="${jacocoReportFile}" append="false"/>
<delete file="${jacocoReportFile}"/>
</target>
</project>
Two mandatory params you should pass when invoking this script
-Dworkspace=$WORKSPACE
use it to point to your jenkins workspace and -Djacoco.host=yourappserver.com host without http://
Also notice that I put my jacocoant.jar to ${workspace}/tools/jacoco/jacocoant.jar
What should I do next?
Did you start your app server with jacocoagent.jar?
Did you put ant script and jacocoant.jar in your jenkins workspace?
If yes the last step is to configure a jenkins build. Here is the strategy:
Invoke ant target jacocoReset to reset all previously collected data.
Run your tests
Invoke ant target jacocoReport to get report
If everything is right, you will see it-jacoco.exec in your build workspace.
Look at the screenshot, I also have ant installed in my workspace in $WORKSPACE/tools/ant dir, but you can use one that is installed in your jenkins.
How to push this report in sonar?
Maven sonar:sonar will do the job (don't forget to configure it), point it to main pom.xml so it will run through all modules. Use sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.exec parameter to tell sonar where your integration test report is located. Every time it will analyse new module classes, it will look for information about coverage in it-jacoco.exec.
I already have jacoco.exec in my `target` dir, `mvn sonar:sonar` ignores/removes it
By default mvn sonar:sonar does clean and deletes your target dir, use sonar.dynamicAnalysis=reuseReports to avoid it.
I found another solution for new Sonar versions where JaCoCo's binary report format (*.exec) was deprecated and the preferred format is XML (SonarJava 5.12 and higher).
The solution is very simple and similar to the previous solution with *.exec reports in parent directory from this topic: https://stackoverflow.com/a/15535970/4448263.
Assuming that our project structure is:
moduleC - aggregate project's pom
|- moduleA - some classes without tests
|- moduleB - some classes depending from moduleA and tests for classes in both modules: moduleA and moduleB
You need following maven build plugin configuration in aggregate project's pom:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<id>prepare-and-report</id>
<goals>
<goal>prepare-agent</goal>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/../target/site/jacoco-aggregate</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Then build project with maven:
mvn clean verify
And for Sonar you should set property in administration GUI:
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml
or using command line:
mvn sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml
Description
This creates binary reports for each module in default directories: target/jacoco.exec. Then creates XML reports for each module in default directories: target/site/jacoco/jacoco.xml. Then creates an aggregate report for each module in custom directory ${project.basedir}/../target/site/jacoco-aggregate/ that is relative to parent directory for each module. For moduleA and moduleB this will be common path moduleC/target/site/jacoco-aggregate/.
As moduleB depends on moduleA, moduleB will be built last and its report will be used as an aggregate coverage report in Sonar for both modules A and B.
In addition to the aggregate report, we need a normal module report as JaCoCo aggregate reports contain coverage data only for dependencies.
Together, these two types of reports providing full coverage data for Sonar.
There is one little restriction: you should be able to write a report in the project's parent directory (should have permission). Or you can set property jacoco.skip=true in root project's pom.xml (moduleC) and jacoco.skip=false in modules with classes and tests (moduleA and moduleB).
I'll post my solution as it it subtly different from others and also took me a solid day to get right, with the assistance of the existing answers.
For a multi-module Maven project:
ROOT
|--WAR
|--LIB-1
|--LIB-2
|--TEST
Where the WAR project is the main web app, LIB 1 and 2 are additional modules the WAR depends on and TEST is where the integration tests live.
TEST spins up an embedded Tomcat instance (not via Tomcat plugin) and runs WAR project and tests them via a set of JUnit tests.
The WAR and LIB projects both have their own unit tests.
The result of all this is the integration and unit test coverage being separated and able to be distinguished in SonarQube.
ROOT pom.xml
<!-- Sonar properties-->
<sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<!-- build/plugins (not build/pluginManagement/plugins!) -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<executions>
<execution>
<id>agent-for-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<append>true</append>
<destFile>${sonar.jacoco.reportPath}</destFile>
</configuration>
</execution>
<execution>
<id>agent-for-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<append>true</append>
<destFile>${sonar.jacoco.itReportPath}</destFile>
</configuration>
</execution>
</executions>
</plugin>
WAR, LIB and TEST pom.xml will inherit the the JaCoCo plugins execution.
TEST pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<skipTests>${skip.tests}</skipTests>
<argLine>${argLine} -Duser.timezone=UTC -Xms256m -Xmx256m</argLine>
<includes>
<includes>**/*Test*</includes>
</includes>
</configuration>
</execution>
</executions>
</plugin>
I also found Petri Kainulainens blog post 'Creating Code Coverage Reports for Unit and Integration Tests With the JaCoCo Maven Plugin' to be valuable for the JaCoCo setup side of things.
There is a way to accomplish this. The magic is to create a combined jacoco.exec file. And with maven 3.3.1 there is an easy way to get this. Here my profile:
<profile>
<id>runSonar</id>
<activation>
<property>
<name>runSonar</name>
<value>true</value>
</property>
</activation>
<properties>
<sonar.language>java</sonar.language>
<sonar.host.url>http://sonar.url</sonar.host.url>
<sonar.login>tokenX</sonar.login>
<sonar.jacoco.reportMissing.force.zero>true</sonar.jacoco.reportMissing.force.zero>
<sonar.jacoco.reportPath>${jacoco.destFile}</sonar.jacoco.reportPath>
<jacoco.destFile>${maven.multiModuleProjectDirectory}/target/jacoco_analysis/jacoco.exec</jacoco.destFile>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<append>true</append>
<destFile>${jacoco.destFile}</destFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.2</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
If you add this profile to your parent pom and call mvn clean install sonar:sonar -DrunSonar you get the complete coverage.
The magic here is maven.multiModuleProjectDirectory. This folder is always the folder where you started your maven build.
The configuration I use in my parent level pom where I have separate unit and integration test phases.
I configure the following properties in the parent POM
Properties
<maven.surefire.report.plugin>2.19.1</maven.surefire.report.plugin>
<jacoco.plugin.version>0.7.6.201602180812</jacoco.plugin.version>
<jacoco.check.lineRatio>0.52</jacoco.check.lineRatio>
<jacoco.check.branchRatio>0.40</jacoco.check.branchRatio>
<jacoco.check.complexityMax>15</jacoco.check.complexityMax>
<jacoco.skip>false</jacoco.skip>
<jacoco.excludePattern/>
<jacoco.destfile>${project.basedir}/../target/coverage-reports/jacoco.exec</jacoco.destfile>
<sonar.language>java</sonar.language>
<sonar.exclusions>**/generated-sources/**/*</sonar.exclusions>
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
<sonar.coverage.exclusions>${jacoco.excludePattern}</sonar.coverage.exclusions>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/coverage-reports</sonar.jacoco.reportPath>
<skip.surefire.tests>${skipTests}</skip.surefire.tests>
<skip.failsafe.tests>${skipTests}</skip.failsafe.tests>
I place the plugin definitions under plugin management.
Note that I define a property for surefire (surefireArgLine) and failsafe (failsafeArgLine) arguments to allow jacoco to configure the javaagent to run with each test.
Under pluginManagement
<build>
<pluginManagment>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<fork>true</fork>
<meminitial>1024m</meminitial>
<maxmem>1024m</maxmem>
<compilerArgument>-g</compilerArgument>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<forkCount>4</forkCount>
<reuseForks>false</reuseForks>
<argLine>-Xmx2048m ${surefireArgLine}</argLine>
<includes>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/*IT.java</exclude>
</excludes>
<skip>${skip.surefire.tests}</skip>
</configuration>
</plugin>
<plugin>
<!-- For integration test separation -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.19.1</version>
</dependency>
</dependencies>
<configuration>
<forkCount>4</forkCount>
<reuseForks>false</reuseForks>
<argLine>${failsafeArgLine}</argLine>
<includes>
<include>**/*IT.java</include>
</includes>
<skip>${skip.failsafe.tests}</skip>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- Code Coverage -->
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<configuration>
<haltOnFailure>true</haltOnFailure>
<excludes>
<exclude>**/*.mar</exclude>
<exclude>${jacoco.excludePattern}</exclude>
</excludes>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.check.lineRatio}</minimum>
</limit>
<limit>
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.check.branchRatio}</minimum>
</limit>
</limits>
</rule>
<rule>
<element>METHOD</element>
<limits>
<limit>
<counter>COMPLEXITY</counter>
<value>TOTALCOUNT</value>
<maximum>${jacoco.check.complexityMax}</maximum>
</limit>
</limits>
</rule>
</rules>
</configuration>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${jacoco.destfile}</destFile>
<append>true</append>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${jacoco.destfile}</dataFile>
<outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
<skip>${skip.surefire.tests}</skip>
</configuration>
</execution>
<execution>
<id>pre-integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${jacoco.destfile}</destFile>
<append>true</append>
<propertyName>failsafeArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>report-integration</goal>
</goals>
<configuration>
<dataFile>${jacoco.destfile}</dataFile>
<outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
<skip>${skip.failsafe.tests}</skip>
</configuration>
</execution>
<!-- Disabled until such time as code quality stops this tripping
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<dataFile>${jacoco.destfile}</dataFile>
</configuration>
</execution>
-->
</executions>
</plugin>
...
And in the build section
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<!-- for unit test execution -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<!-- For integration test separation -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
<plugin>
<!-- For code coverage -->
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
....
And in the reporting section
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven.surefire.report.plugin}</version>
<configuration>
<showSuccess>false</showSuccess>
<alwaysGenerateFailsafeReport>true</alwaysGenerateFailsafeReport>
<alwaysGenerateSurefireReport>true</alwaysGenerateSurefireReport>
<aggregate>true</aggregate>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<configuration>
<excludes>
<exclude>**/*.mar</exclude>
<exclude>${jacoco.excludePattern}</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</reporting>
As Sonars sonar.jacoco.reportPath, sonar.jacoco.itReportPath and sonar.jacoco.reportPaths have all been deprecated, you should use sonar.coverage.jacoco.xmlReportPaths now. This also has some impact if you want to configure a multi module maven project with Sonar and Jacoco.
As #Lonzak pointed out, since Sonar 0.7.7, you can use Sonars report aggragation goal. Just put in you parent pom the following dependency:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<id>report</id>
<goals>
<goal>report-aggregate</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
As current versions of the jacoco-maven-plugin are compatible with the xml-reports, this will create for every module in it's own target folder a site/jacoco-aggregate folder containing a jacoco.xml file.
To let Sonar combine all the modules, use following command:
mvn -Dsonar.coverage.jacoco.xmlReportPaths=full-path-to-module1/target/site/jacoco-aggregate/jacoco.xml,module2...,module3... clean verify sonar:sonar
To keep my answer short and precise, I did not mention the maven-surefire-plugin and
maven-failsafe-plugin dependencies. You can just add them without any other configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.jacoco.reportPath>${user.dir}/target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.jacoco.itReportPath>${user.dir}/target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.exclusions>
file:**/target/generated-sources/**,
file:**/target/generated-test-sources/**,
file:**/target/test-classes/**,
file:**/model/*.java,
file:**/*Config.java,
file:**/*App.java
</sonar.exclusions>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
<propertyName>surefire.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.itReportPath}</destFile>
<append>true</append>
<propertyName>failsafe.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-report-integration</id>
<goals>
<goal>report-integration</goal>
</goals>
</execution>
</executions>
</plugin>
This sample works very well for me :
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
<!--<excludes>
<exclude>com.asimio.demo.rest</exclude>
<exclude>com.asimio.demo.service</exclude>
</excludes>-->
<propertyName>testArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
</configuration>
</execution>
<execution>
<id>merge-results</id>
<phase>verify</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<directory>${project.build.directory}/coverage-reports</directory>
<includes>
<include>*.exec</include>
</includes>
</fileSet>
</fileSets>
<destFile>${project.build.directory}/coverage-reports/aggregate.exec</destFile>
</configuration>
</execution>
<execution>
<id>post-merge-report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/aggregate.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<argLine>${surefireArgLine}</argLine>
<!--<skipTests>${skip.unit.tests}</skipTests>-->
<includes>
<include>**/*Test.java</include>
<!--<include>**/*MT.java</include>
<include>**/*Test.java</include>-->
</includes>
<!-- <skipTests>${skipUTMTs}</skipTests>-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<!--<skipTests>${skipTests}</skipTests>
<skipITs>${skipITs}</skipITs>-->
<argLine>${testArgLine}</argLine>
<includes>
<include>**/*IT.java</include>
</includes>
<!--<excludes>
<exclude>**/*UT*.java</exclude>
</excludes>-->
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
You can call a ant task called merge on maven, to put all coverage files (*.exec) together in the same file.
If you are run unit tests use the phase prepare-package, if you run integration test so use post-integration-test.
This site has an example to how call jacoco ant task in maven project
You can use this merged file on sonar.
to have unit-testing AND integration-testing you can use maven-surefire-plugin and maven-failsafe-plugin with restricted includes/excludes. I was playing with CDI while getting in touch with sonar/jacoco, so i ended up in this project:
https://github.com/FibreFoX/cdi-sessionscoped-login/
Maybe it helps you a little bit. in my pom.xml i use "-javaagent" implicit by setting the argLine-option in the configuration-section of the specified testing-plugins.
Explicit using ANT in MAVEN projects is something i would not give a try, for me its to much mixing two worlds.
I only have a single-module maven project, but maybe it helps you to adjust yours to work.
note: maybe not all maven-plugins are up2date, maybe some issues are fixed in later versions
As stated in the Jacoco Wiki, you could also generate a new reporting-module:
Strategy: Module with Dependencies: The problems with aggregator
projects can be solved with an extra "reporting" module. In a
multi-module Maven project a separate module is defined that does not
contribute actual content but creates a combined coverage report. It
defines a dependency to all the modules that should be included in the
combined report. The "reporting" module would be built after its
dependencies and have access to the exec files as well as class and
source files from projects it depends on. This strategy seems to work
best with the current Maven architecture. From a user's perspective
one could argue that such a separate module would bloat the build
definition. Or, that the separate module cannot have any submodules
from which it could consume exec or class files. However, compared to
the other strategies these drawbacks seem rather minor and can be
handled in a consistent manner.
This is especially helpful if your modularisation is more complex than one parent with some child modules.
Your reporting pom could look something like:
<dependencies>
<dependency>
<groupId>org.sonarqube</groupId>
<artifactId>module1</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.sonarqube</groupId>
<artifactId>module2</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<goals>
<goal>report-aggregate</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>

Resources