java/jacoco-argLine

JaCoCo uses the Surefire argLine to add a javaagent which collects the coverage data. If you customize the argLine i.e. for increasing the heap size (-Xmx1536m) you must preserve the possibility for JaCoCo to still add its javaagent. This is best done by @argLine (see explanation below).

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <argLine>@{argLine} ${surefireArgLine} -Xmx1536m</argLine>
    </configuration>
</plugin>

In the following I walk you through the possible variations and traps of them.

Simple usage

When you start using Jacoco it’s easy, you add the plugin configuration like below, start your test with mvn test and you have a file with execution data (target/jacoco.exec).

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.5</version>
    <executions>
        <execution>
            <id>default-prepare-agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Adjust Surefire argLine in pom.xml

Next you maybe want to give your tests more heap size with -Xmx1536m.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <argLine>-Xmx1536m</argLine>
    </configuration>
</plugin>

The heap size is increased, but jacoco.exec is missing and hence JaCoCo was not executed.

Now we need to understand how the JaCoCo Maven plug-in works. JaCoCo uses a javaagent to collect the execution data, for that the prepare-agent goal sets the argLine property which is then consumed by surefire:test argLine. You can see this in the log:

[INFO] --- jacoco-maven-plugin:0.8.5:prepare-agent (default-prepare-agent) @ jacoco-argLine ---
[INFO] argLine set to -javaagent:<...>org.jacoco.agent-0.8.5-runtime.jar=destfile=<...>target\\jacoco.exec

But, if the argLine is already defined in the configuration, surefire will not read the property and therefore the javaagent will not be added.

This can be fixed by adding a placeholder in the configuration which then can again consume the property.

<configuration>
    <argLine>${argLine} -Xmx1536m</argLine>
</configuration>

Now the argLine set by prepare-agent is consumed by ${argLine} and jacoco.exec is written again.

Adjust Surefire argLine with user property

Sometimes you don’t want to hardcode everything in the pom.xml and use user properties. E. g. mvn clean test -DargLine="-Dfoo=bar". With the configuration above jacoco.exec again is not written as ${argLine} is replaced by -Dfoo=bar and no placeholder is left to consume the jacoco argLine.

Since Version 2.17 Surefire provides a solution for this: late property evaluation. With @{argLine} evaluation is done from surefire itself. So you could use:

<configuration>
    <argLine>@{argLine} ${argLine} -Xmx1536m</argLine>
</configuration>

Although two argLine variables are confusing it works when called with a argLine user property (-DargLine="-Dfoo=bar"), but it fails without due to the duplicate javaagent:

[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
[ERROR] Command was cmd.exe /X /C ""<...>\bin\java" -javaagent:<...> -javaagent:<...>  -Xmx1536m -jar <...>\surefirebooter17379281364314664758.jar <...>

Solution

As already @{argLine} consumes the javaagent you can freely rename the other variable as you wish.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <argLine>@{argLine} ${surefireArgLine} -Xmx1536m</argLine>
    </configuration>
</plugin>

This can be called successfully with mvn clean test -DsurefireArgLine="-Dfoo=bar". But without it will fail due to the not replaced surefireArgLine variable.

[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
[ERROR] Command was cmd.exe /X /C ""<...>\bin\java" -javaagent:<...>  ${surefireArgLine} -Xmx1536m -jar <...>\surefirebooter17379281364314664758.jar <...>

When you add and empty surefireArgLine property you are prepared for both cases:

<properties>
    <surefireArgLine></surefireArgLine>
</properties>
'; ?>