Jenkins and Jacoco Integration Test Coverage - java

I just added Jacoco on my maven dependencies to run integration tests. Then, I created an integration test to test my controller. For example, I tested my HTTP response codes, the headers and the response resources. After that, I created a profile on maven that starts an embedded tomcat. So, everytime I want to run my integration tests, I just put the profile on the maven goals. However, when I execute the build on Jenkins and Sonar reads the reports from Jacoco, the reports says that I have not tested my controller. The question is: How I tell Jacoco that I have passed through my Controllers, Services and Repositories?
Thanks to all!

Are you getting any Integration Coverage, or just 0%?
It can be quite tricky to set up Integration Test Coverage using maven and Sonar.
Check there is a jacoco file produced when the IT tests are run.
Check your POM set up compared to this...
<properties>
<!-- Jacoco Properties -->
<jacoco.version>0.7.4.201502262128</jacoco.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
<sonar.jacoco.itReportPath>${project.basedir}/target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.language>java</sonar.language>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>prepare-unit-test-agent</id>
<configuration>
</configuration>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>prepare-it-test-agent</id>
<configuration>
<propertyName>jacoco.agent.argLine</propertyName>
<destFile>${sonar.jacoco.itReportPath}</destFile>
<append>true</append>
</configuration>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<argLine>${jacoco.agent.argLine}</argLine>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Link to GitHub example
BeyondCoding.net

Related

Jacoco aggregate report is generating Exec file instead of XML

We have a multi-module maven project. We are using java8.
-Parent
-- Child 1
-- Child 2
-- Coverage-Report
All projects have unit test cases, those all are working good and have more than 85% of coverage. Parent pom.xml file has jacoco-profile and jacoco-maven-plugin plugin as below
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.6</version>
<configuration>
<destFile>${sonar.coverage.jacoco.xmlReportPaths}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
In Coverage-Report module, there is only pom.xml which is for aggregating report. It has profile as jacoco as below
<profile>
<id>jacoco</id>
<activation/>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
To generate the report, we are using below command
mvn clean verify -Pjacoco
We do see the file getting generated which is mentioned in parent pom.xml
<sonar.coverage.jacoco.xmlReportPaths>${maven.multiModuleProjectDirectory}/ocapi-promotion-service-coverage-report/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
However this file, jacoco.xml, is not proper XML. It has some encoded character as below. (few lines from that file)
��ca6191af5ae0-1a24a201}-�Sy}-ƌ|pW�\����;org/springframework/context/annotation/BeanAnnotationHelper�w~�j�zI�ZMorg/springframework/boot/autoconfigure/condition/FilteringSpringBootCondition������e֢+org/sp
On jenkins we see below error
Caused by: java.nio.charset.MalformedInputException: Input length = 1
I have followed an article from sonar source community https://community.sonarsource.com/t/coverage-test-data-importing-jacoco-coverage-report-in-xml-format/12151 which gives some steps. But I am not able to generate XML file. Please help.

Get IT test in Sonar trough maven

Gooday,
I’m trying to get my IT in to the test coverage in sonar. I have a multi module project and I want this to work for all the modules. So as far as I got it through the documentation I found:
https://docs.sonarqube.org/display/PLUG/Usage+of+JaCoCo+with+Java+Plugin
https://github.com/SonarSource/sonar-scanning-examples/tree/master/sonarqube-scanner-maven (witch are outdated btw)
http://www.eclemma.org/jacoco/trunk/doc/maven.html
Integrating JaCoCo with SONAR for unit and integration test coverage (autdated its prity based on old maven and sonar stuff and our sonar is a bit newer (6.3.1)).
But when I run it the test seems to have 0% so obviously I’m doing something wrong. Some in put on where I did go wrong would be nice.
My main Pom:
<properties>
<maven-failsafe-plugin.version>2.20.1</maven-failsafe-plugin.version>
<maven-surefire-plugin.version>2.20.1</maven-surefire-plugin.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPaths>${project.basedir}/../target/</sonar.jacoco.reportPaths>
<argLine>-Xmx256m -XX:MaxPermSize=200m</argLine>
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<configuration>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent-for-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.basedir}/../target/jacoco-ut.exec</destFile>
</configuration>
</execution>
<execution>
<id>agent-for-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${project.basedir}/../target/jacoco-it.exec</destFile>
</configuration>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin>
</plugins>
</build>
Ive been messing with for my feeling a whole day and have not found a clear cut answer what I am doing wrong. So some input would be very helpful
well the coverage for both unit and integration tests is a bit fragile...
The configuration you have looks ok. I think what may happens is that the "argLine" property is replaced or not correctly set for the surefire or failsafe plugin. If you run the mvn goals with -X have a close look what happens when failsafe starts what its value is. The argLine should contain the jacoco agent to collect the coverage information.
Another thing: failsafe might write the coverage results into the same jacoco.exec file as surefire.
What I've done (not sure if it's the smartest of all ways): put all things in a profile and use custom properties for the jacoco-plugin and seperate files for the coverage so the sonar report can pick them up:
The sonar-jacoco-listeners is only required if you want to know what test covers which production code. In sonar this is then shown in the green bar what tests called the code.
Other than that:
The pom has some properties:
<surefire.jvm.args></surefire.jvm.args>
<failsafe.jvm.args></failsafe.jvm.args>
<jacoco.append>true</jacoco.append>
</properties>
These can be set if needed and the config uses its own properties to not conflict with the argLine (which is the default for both surefire and failsafe)
The sonar.jacoco.reportPath can be used to write one file for all maven modules, in case some integration tests are in a different module and you want to measure the coverage as well (not too nice code-wise, but well... reality and stuff):
<sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
Here my coverage profile: (adopt the includes: my/packages/* pattern below!)
<profile>
<dependencies>
<dependency>
<groupId>org.codehaus.sonar-plugins.java</groupId>
<artifactId>sonar-jacoco-listeners</artifactId>
<version>3.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<!-- prepare configuration for surefire tests -->
<execution>
<id>prepare-agent</id>
<phase>initialize</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<propertyName>jacoco.agent.argLine</propertyName>
<append>true</append>
</configuration>
</execution>
<!-- prepare configuration for failsafe integration tests -->
<execution>
<id>prepare-agent-integration</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.itReportPath}</destFile>
<propertyName>jacoco.agent.it.argLine</propertyName>
<append>true</append>
</configuration>
</execution>
</executions>
<configuration>
<includes>
<include>my/packages/*</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<property>
<name>listener</name>
<value>org.sonar.java.jacoco.JUnitListener</value>
</property>
</properties>
<argLine>${jacoco.agent.argLine} ${surefire.jvm.args}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<argLine>${jacoco.agent.it.argLine} ${failsafe.jvm.args}</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
So the principle is the same, setup the jacoco agent in the correct phase and run the tests. I assume the jacoco agent is not properly setup or your argLine conflicts with something happening during your build.

BUILD SUCCESS even after failures in test

I have added cucumber report plugin in pom.xml as follows:
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>${maven.cucumber.reporting.version}</version>
<executions>
<execution>
<id>execution</id>
<phase>test</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<projectName>cucumber-jvm-example</projectName>
<outputDirectory>${project.build.directory}/cucumber-html-reports</outputDirectory>
<cucumberOutput>${project.build.directory}/cucumber.json</cucumberOutput>
<parallelTesting>false</parallelTesting>
</configuration>
</execution>
</executions>
</plugin>
which will generate reports only if there is no failure, but to generate report even after failure I had to add:
<testFailureIgnore>true</testFailureIgnore>
in the maven surefire plugin, this is generation report even after failure in test but problem is BUILD SUCCESS message generated and it should be BUILD FAILURE.
any idea?

Run Maven plugin just before deploy to remote repo

In my maven project I use the pgp plugin to sign my jars. I need to do this only when deploying to remote repo, but not when installing to local repo. So I tried to set the phase to deploy.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>deploy</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
With that configuration maven first deploys to remote repo and theh signs my jars...
I read that plugins are executed in the order they are defined in POM file, so I tried to configure deploy-plugin after sign plugin, but that didnt have any effect
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>deploy</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<executions>
<execution>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
How can I achieve that sign plugin is not executed on install, but on deploy before artifacts are uploaded? I'm using maven3.
First i would suggest to update maven-gpg-plugin to an more up-to-date version cause this version 1.1 is of 2010..Apart from that i would suggest to keep the defaults of the plugins which means the binding of maven-deploy-plugin as the deploy life cycle and for the maven-gpg-plugin the verify life cycle phase which is not ideal if you have integration tests. In such cases it makes sense to define a profile which is activated only in release cases to prevent confusions with integration test.
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
<executions>
<execution>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
I have seen project putting the gpg-plugin in verify phase.
May I know what version of Maven you are using? I believe the plugin in same phase should run in order it is defined, after Maven 2.0.10 (or probably earlier). However as maven-deploy-plugin is default binding for deploy phase, I am not clear if the ordering will be in effect

Unable to get Jacoco to work with Powermockito using offline instrumentation

Given that Jacoco doesn't play nicely with PowerMockito when instrumenting "on the fly", I've been trying to configure offline instrumentation in the hope this will give me proper unit test coverage for classes that use PowerMockito.
I've setup my pom as below but I still get zero % coverage on my test class. Any help much appreciated as it's driving me slowly bonkers!
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>mandy</groupId>
<artifactId>jacoco-test</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>jacoco-test Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<powermock.version>1.5.4</powermock.version>
<jacoco.version>0.7.1.201405082137</jacoco.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<classifier>runtime</classifier>
<version>${jacoco.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>instrument</id>
<phase>process-classes</phase>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>restore-report</id>
<phase>prepare-package</phase>
<goals>
<goal>restore-instrumented-classes</goal>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<!--<argLine>${argLine}</argLine>-->
<systemPropertyVariables>
<!-- JaCoCo runtime must know where to dump coverage: -->
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
<finalName>jacoco-test</finalName>
</build>
</project>
here is my class under test:
public class Utils {
private Utils() {
}
public static String say(String s) {
return "hello:"+s;
}
}
here is my test:
#RunWith(PowerMockRunner.class)
#PrepareOnlyThisForTest(Utils.class)
#PowerMockIgnore("org.jacoco.agent.rt.*")
public class UtilsTest {
#Test
public void testSay() throws Exception {
PowerMockito.mockStatic(Utils.class);
Mockito.when(Utils.say(Mockito.anyString())).thenReturn("hello:mandy");
assertEquals("hello:mandy", Utils.say("sid"));
}
}
I run mvn clean install which generates the jacoco.exe
Coverage report (generated from jacoco.exec using an ant script ):-
This pom worked for me:
<build>
<finalName>final-name</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.2.201409121644</version>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
See this link.
I saw the same behavior, though after following the thread on the GitHub issue it seems to be fixed in 1.6.5, which proved true for me.
Hopefully this will save someone a headache later :).
Working configuration with:
jacoco-maven-plugin 0.7.7.201606060606
powermock 1.6.5
I am not using offline instrumentation.
For me this sample of Offline Instrumentation works well.
But it turns in my case that there is a simplier solution: just do not include the tested class in #PrepareForTest({}) annotation before its declaration.
I used Jacoco offline instrumentation and after execution of test restore ed original classes with help of "restore-instrumented-classes" goal. My JaCoCo configuration look like this:
<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>
</execution>
<execution>
<id>jacoco-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>jacoco-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>*</exclude>
</excludes>
</configuration>
</plugin>
I made it work using the javaagent of PowerMock.
see here: https://github.com/powermock/powermock/wiki/PowerMockAgent
Remove the #RunWith annotations, put the PowerMockRule as described in the link above. Make it public.
Put the following line in the maven-surefire-plugin configuration:
-javaagent:${org.powermock:powermock-module-javaagent:jar}
(used the technique described here : Can I use the path to a Maven dependency as a property?)
<?xml version="1.0" encoding="UTF-8"?>
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.stackoverflow</groupId>
<artifactId>q2359872</artifactId>
<version>2.0-SNAPSHOT</version>
<name>q2359872</name>
<properties>
<!-- Must be listed in the dependencies section otherwise it will be null. -->
<my.lib>${org.jmockit:jmockit:jar}</my.lib>
</properties>
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>1.11</version>
</dependency>
</dependencies>
<build>
<defaultGoal>generate-sources</defaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Example usage: -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
<configuration>
<executable>echo</executable>
<arguments>
<argument>path to jar=</argument>
<argument>${org.jmockit:jmockit:jar}</argument>
<argument>my.lib=</argument>
<argument>${my.lib}</argument>
</arguments>
</configuration>
</plugin>
<!-- end of Example usage -->
</plugins>
</build>
</project>
I ended up using offline instrumentation and Jacoco (similar to what you have done) in conjunction with sonar and I was able to get the coverage numbers from that.
I was also facing the same issue. I was able to generate report partially. I have used both these tags for my test cases #RunWith(PowerMockRunner.class)
#PrepareForTest({}). And the report was not getting generated for the test cases where i used the above mentioned tags. But for one of the test case there was only this tag #RunWith(PowerMockRunner.class). Somehow the report was getting generated for that case. And also i have never used offline instrumentation. When i tried using the offline instrumentation i was getting error saying that the class was already instrumented. I tried various scenarios and followed various links but could not generate the report. Finally as per the above comment i upgraded my version of powermock from 1.5.5 to 1.6.5 and i was able to generate the report. Following is my pom.xml entry
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.5.201505241946</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<destFile>${basedir}/target/jacoco.exec</destFile>
<!--
Sets the name of the property containing the settings
for JaCoCo runtime agent.
-->
</configuration>
</execution>
<execution>
<!--<id>post-unit-test</id>
<phase>test</phase>-->
<id>default-report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${basedir}/target/jacoco.exec</dataFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${basedir}/target/jacoco-ut</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Following is my entry in pom .xml for maven-surefire-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>#{argLine}</argLine>
<skipTests>false</skipTests>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
#{argLine} was set as a property
<properties>
<argLine>-noverify -Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=512m</argLine>
</properties>
And upgraded my powermock version from 1.5.5 to 1.6.5 . Finally i could see my report generation for the classes where i used the following tags in my test cases
#RunWith(PowerMockRunner.class) #PrepareForTest({})
Use below maven plugin code snippet this works fine in jenkins as well as in local and shows full code coverage for PowermockRunner unit tests
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<id>pre-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<append>true</append>
</configuration>
</execution>
<execution>
<id>pre-integ-test</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<append>true</append>
</configuration>
</execution>
<execution>
<id>jacoco-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>jacoco-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
</executions>
<configuration>
<excludes>
<exclude>*</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
Code Coverage with JaCoCo explained the reason
The simplest way to use JaCoCo it is — on-the-fly instrumentation with using JaCoCo Java Agent. In this case a class in modified when it is being loaded. You can just run you application with JaCoCo agent and a code coverage is calculated. This way is used by Eclemma and Intellij Idea. But there is a big issue. PowerMock instruments classes also. Javassist is used to modify classes. The main issue is that Javassist reads classes from disk and all JaCoCo changes are disappeared. As result zero code coverage for classes witch are loaded by PowerMock class loader.
We are going to replace Javassist with ByteBuddy (#727) and it should help to resolve this old issue. But right now there is NO WAY TO USE PowerMock with JaCoCo On-the-fly instrumentation. And no workaround to get code coverage in IDE.
JaCoCo Offline Instrumentation can solve this problem.
The sample of Offline Instrumentation fixed my problem .
I have tried these versions of the below softwares; they work together and generate the jacoco report without any extra effort. I use the gradle build tool with powermock, mockito and wiremock.
powermock-api-mockito2:2.0.2
powermock-module-junit4:2.0.2
gradle 5.6.2
The above correctly generates the jacoco coverage report.
I had same issue with JaCoCo On-the-fly and PowerMock. 0% code coverage was generated every time
Found out that JaCoCo version 0.7.7.201606060606 and PowerMock version 1.6.2 are compatible and code coverage is generated successfully.
The report is correct. The provided test leads to no coverage as you mock what happens when calling the method "say". One should never mock the "instance/class under test", only do this for the dependencies and surroundings of the test subject.
In this case: The code return "hello:"+s; is never reached by the test and the constructor of Utils is not called. There is no coverage displayed as there is no test coverage of these lines at all.
Nevertheless using JaCoCo and PowerMock together is not trivial. I am currently looking for how to get it to run, too. Maybe your provided test is just unluckily written and JaCoCo is already working as it should?

Categories