Tomcat7 Maven Plugin and JaCoCo

shelley picture shelley · Apr 15, 2013 · Viewed 9.8k times · Source

Is there any way to get code coverage using JaCoCo with the tomcat7-maven-plugin embedded instance?

The jacoco-maven-plugin is configured in my WAR's POM to instrument my unit tests, but I'm not sure how to attach the jacoco agent to the embedded Tomcat instance to instrument my integration tests that run against Tomcat. Given that the Tomcat instance is embedded, I'm not sure if this approach is possible. Is there any other way to accomplish this? I can probably switch from using the Tomcat Maven Plugin to using Cargo to get coverage, but I'd prefer to stick with the Tomcat plugin if possible.

Here are a few relevant snippets from my POM:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.6.2.201302030002</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.14</version>
    <executions>
        <execution>
            <id>integration-tests</id>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.1</version>
    <configuration>
        <systemProperties>
            <!-- as expected, this system property doesn't work since Tomcat is embedded, but this is the type of config I'm looking for -->
            <JAVA_OPTS>-javaagent:${project.build.directory}/${jacoco.jar}=destfile=${project.build.directory}/jacoco.exec,append=true</JAVA_OPTS>
        </systemProperties>
    </configuration>
    <executions>
        <execution>
            <id>tomcat-startup</id>
            <goals>
                <goal>run-war-only</goal>
            </goals>
            <phase>pre-integration-test</phase>
            <configuration>
                <fork>true</fork>
            </configuration>
        </execution>
        <execution>
            <id>tomcat-shutdown</id>
            <goals>
                <goal>shutdown</goal>
            </goals>
            <phase>post-integration-test</phase>
        </execution>
    </executions>
</plugin>

Versions: Maven 3.0.4, Tomcat Maven Plugin 2.1, Jacoco 0.6.2.201302030002, Java 7

Answer

Koder picture Koder · Jan 27, 2015

I know its been awhile since the question was posted but I don't feel the answer really addressed the root of the problem. Code coverage may work with failsafe or surefire if you are running tests within those plugins. However, if you just want to monitor tomcat with jacoco to get a coverage report current information doesn't provide that. I found that the tomcat7-maven-plugin doesn't allow you to inject the -javaagent for jacoco by simply providing JAVA_OPTS. Switching to cargo I was able to do that like so.

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.2.201409121644</version>
    <configuration>
        <destFile>${sonar.jacoco.reportPath}</destFile>
        <dataFile>${sonar.jacoco.reportPath}</dataFile>
        <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
        <classDumpDir>${project.reporting.outputDirectory}/jacoco-it/classes</classDumpDir>
        <skip>${skipITs}</skip>
    </configuration>
    <executions>
        <execution>
            <id>jacoco-agent</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
            <configuration>
                <destFile>${sonar.jacoco.reportPath}</destFile>
                <propertyName>jacoco.agent.itArgLine</propertyName>
            </configuration>
        </execution>
        <execution>
            <id>jacoco-report</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>dump</goal>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>
    <plugin>
    <groupId>org.codehaus.cargo</groupId>
    <artifactId>cargo-maven2-plugin</artifactId>
    <version>1.4.11</version>
    <configuration>
        <skip>${skipITs}</skip>
        <container>
            <containerId>tomcat7x</containerId>
            <zipUrlInstaller>
                <url>http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.16/bin/apache-tomcat-7.0.16.zip
                </url>
                <downloadDir>${project.build.directory}/downloads</downloadDir>
                <extractDir>${project.build.directory}/extracts</extractDir>
            </zipUrlInstaller>
            <dependencies>
                <dependency>
                    <groupId>ojdbc</groupId>
                    <artifactId>ojdbc6</artifactId>
                </dependency>
            </dependencies>
        </container>
        <configuration>
            <home>${project.build.directory}/catalina-base</home>
            <properties>
                <cargo.jvmargs>${jacoco.agent.itArgLine},output=tcpserver,port=6300 -Drunmode=TEST</cargo.jvmargs>
                <cargo.servlet.port>9090</cargo.servlet.port>
            </properties>
            <configfiles>
                <configfile>
                    <file>${basedir}/src/test/conf/context.xml</file>
                    <todir>conf/Catalina/localhost/</todir>
                    <tofile>context.xml.default</tofile>
                </configfile>
            </configfiles>
        </configuration>
    </configuration>
    <executions>
        <execution>
            <id>start-tomcat</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>stop-tomcat</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

the important parts are:

  1. <plugin><groupId>org.jacoco</groupId> ...<propertyName>jacoco.agent.itArgLine</propertyName>
  2. <cargo.jvmargs>${jacoco.agent.itArgLine},output=tcpserver,port=6300 </cargo.jvmargs>

When report target is run on the jacoco plugin it will create a directory in ${projectbase}/target/site/jacoco-it/index.html with your coverage report. I use this with the soapui-maven-plugin but it could be used with selenium-maven-plugin also.