3
votes

I've configured my project with SonarQube and Jacoco for code coverage. Everything works well except one thing. I divided project in many maven sub modules:

project (pom.xml) - 
|-moduleA (no pom here)
|   |- it (pom.xml) - integration tests for "impl" module
|   |- impl (pom.xml) - implementaion + Unit tests
|-moduelB
|   |- it (pom.xml) - integration tests for "impl" module
|   |- impl (pom.xml) - implementaion + Unit tests
|-moduleC ...

I start build using following command:

mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent -Dmaven.compiler.debug=true install sonar:sonar

The problem is that Jacoco can easily support Unit test coverage inside the same module (so in my case Unit Tests inside impl module) but cannot analyze coverage from it module which itself does not contain any implementation classes. It just contains integration tests for impl module. It's clear for me why it doesn't work. I'm getting such info in Jacoco logs:

No JaCoCo analysis of project coverage can be done since there is no class files.

After I've defined sonar.java.binaries property inside moduleA/it/pom.xml like this:

    <properties>
         <sonar.java.binaries>../impl/target/classes</sonar.java.binaries>
    </properties>

coverage analysis of it still fails, but message in Jacoco logs changes to:

[INFO] Analysing D:\project\moduleA\it\target\jacoco.exec
[WARNING] Coverage information was not collected. Perhaps you forget to include debug information into compiled classes?

I must mention that D:\project\moduleA\it\target\jacoco.exec file exists. I also checked that compiled classes in D:\project\moduleA\impl\target\classes contain debug data (all lines, vars and source).

I was trying with different paths inside sonar.java.binaries but result is always the same. I've tried:

../impl/target/classes
../../impl/target/classes
../../../impl/target/classes
../impl/target
...

How can I configure Jacoco (Sonar) to allow it to find classes binaries in different maven sub module related to jacoco.exec file?

1
Is there a reason why the integration tests are separate by the implemenation? The build configuration would be easier if you follow the Maven Pattern src/main/javafor production code and src/it/test for integration test in the same module.Sandra Parsick
I am searching a solution to the same issue since several days with no luck!!!Antonio Petricca
@SandraParsick in my case it is because the code is spread across several Maven modules (API, Core, Web, etc.) and the IT module then runs a "full stack" test using Arquillian which starts a Wildfly application server. So coverage is to be tracked for the code base of several Maven modules.Boris

1 Answers

0
votes

Based on this question, I resorted to the Maven Ant plugin with JaCoCo's ant task library, which allows richer inclusion trees:

<project ...>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <version>1.8</version>
                <dependencies>
                    <dependency>
                        <groupId>org.jacoco</groupId>
                        <artifactId>org.jacoco.ant</artifactId>
                        <version>${jacoco.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>ant-contrib</groupId>
                        <artifactId>ant-contrib</artifactId>
                        <version>20020829</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>report-it-coverage</id>
                        <phase>post-integration-test</phase>
                        <goals><goal>run</goal></goals>
                        <configuration>
                            <skip>${skipITs}</skip>
                            <target name="report-it-coverage">
                                <taskdef name="jacoco-report" classname="org.jacoco.ant.ReportTask" classpathref="maven.plugin.classpath" />
                                <taskdef resource="net/sf/antcontrib/antcontrib.properties" classpathref="maven.runtime.classpath" />
                                <available file="${jacoco.it-coverage.data}" property="jacoco.exec.file.exists" />
                                <if>
                                    <equals arg1="${jacoco.exec.file.exists}" arg2="true" />
                                    <then>
                                        <echo>Analyzing ITs coverage data from '${jacoco.it-coverage.data}'</echo>
                                        <jacoco-report>
                                            <executiondata>
                                                <file file="${jacoco.it-coverage.data}" />
                                            </executiondata>
                                            <structure name="ROOT">
                                                <classfiles>
                                                    <fileset dir="${project.basedir}/${project.parent.relativePath}">
                                                        <include name="**/target/classes/my/company/package/**/*.class" />
                                                        <exclude name="**/target/classes/my/test/glue/**/*" />
                                                    </fileset>
                                                </classfiles>
                                            </structure>
                                            <html destdir="${project.reporting.outputDirectory}/jacoco-it" />
                                            <xml destfile="${project.build.directory}/jacoco.xml" />
                                        </jacoco-report>
                                    </then>
                                    <else>
                                        <echo>Missing ITs coverage data file '${jacoco.it-coverage.data}'</echo>
                                    </else>
                                </if>
                            </target>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>