I implement my aspect class in Java style:
#Aspect
public class SomeAspect {
#Pointcut("...")
public void somePointcut() {}
#Around("somePointcut()")
public ...
}
I am new to AspectJ. I want to know if there a convenient/centralized way to control the effectiveness of the Pointcut so I can enable/disable them based on some configuration at compile time.
During runtime you can just use an if() pointcut, but I know this is not what you want.
For compile time it depends on how you build your project. I am going to assume you use Maven and the AspectJ Maven Plugin.
Let us further assume that you configure the plugin to run in the process-sources phase like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<configuration>
<!--<showWeaveInfo>true</showWeaveInfo>-->
<source>${java.source-target.version}</source>
<target>${java.source-target.version}</target>
<Xlint>ignore</Xlint>
<complianceLevel>${java.source-target.version}</complianceLevel>
<encoding>${project.build.sourceEncoding}</encoding>
<!--<verbose>true</verbose>-->
<!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
</configuration>
<executions>
<execution>
<!-- IMPORTANT -->
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
Then just add a Maven profile - let us call it skip-aspectj which overwrites the phase to none via <phase/>:
<profiles>
<profile>
<id>skip-aspectj</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<executions>
<execution>
<phase/>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Now if you run your Maven build
normally, the aspects are compiled and applied,
with mvn -P skip-aspectj ... they will be inactive and the whole AspectJ Maven execution just skipped.
Related
I'm currently working on a java project where I need to generate and compile JPA metamodel classes as part of the build. I did some research and found an answer here: Generate the JPA metamodel files using maven-processor-plugin - What is a convenient way for re-generation? that seems like a reasonable solution. The problem is, my project also contains some groovy classes that need to be compiled alongside the java. If I enable the maven-processor-plugin, the maven build will fail as soon as it encounters a java class that depends on a groovy class. Looking at the console output, I can see that maven-processor-plugin is running before the groovy compiler, so those groovy classes have not had a chance to be compiled.
Does anyone know if there is a good way to handle this? Is there some way to break the compilation process up into stages so that I can control what gets processed when?
Here is a snippet of my pom.xml:
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<showWarnings>false</showWarnings>
<compilerId>groovy-eclipse-compiler</compilerId>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-compiler</artifactId>
<version>3.6.0-03</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-eclipse-batch</artifactId>
<version>3.0.7-02</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>4.5-jdk8</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<outputDirectory>${project.build.directory}/../src/main/generated-sources/java/jpametamodel</outputDirectory>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.13.Final</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/../src/main/generated-sources/java/jpametamodel</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
After a good bit of trial and error I finally found a solution that seems to work. maven-processor-plugin can use include/exclude filters to limit the scope of the files it looks at. I added an includes filter that restricts the processing to my domain classes. Now when I build it can process my annotated classes without getting hung up on the groovy files.
My final result ended up looking like this:
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>4.5-jdk8</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<includes>
<include>com/tura/product/domain/*.java</include>
</includes>
<outputDirectory>${project.build.directory}/generated-sources/java</outputDirectory>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
<overwrite>true</overwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.3.13.Final</version>
</dependency>
</dependencies>
</plugin>
I have maven project that use aspectJ for auditing. I'm use Intellij idea. Here is my plugin config in pom file:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>${java.version}</source>
<target>${java.version}</target>
<Xlint>ignore</Xlint>
<complianceLevel>${java.version}</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<!-- IMPORTANT -->
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.10</version>
</dependency>
</dependencies>
</plugin>
When I clean package the aspectJ plugin says:
Join point 'method-execution(java.util.List com.test.getHistories(java.lang.String, java.lang.String))' in Type 'com.test.HistoryService' (HistoryService.java:18) advised by around advice from 'com.test.aspects.AuditLoggerAspect' (AuditLoggerAspect.java:88)
Join point 'method-execution(java.lang.String com.test.getString(int, java.lang.Object))' in Type 'com.test' (AspectTest.java:14) advised by around advice from 'com.test.AuditLoggerAspect' (AuditLoggerAspect.class(from AuditLoggerAspect.java))
This app packaging is WAR and i want to deploy it on Weblogic.
When I deploy it or run test the aspect not work. Why?
I test this aspect and maven plugin config in Java App and it's work good.
When I clean and package the project, the maven-compiler-plugin recompiles the projects after aspectj-compiler-plugin compiled it. So the compiled aspects are removed.
I added the below config to maven-compiler-plugin to solve it:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<!-- IMPORTANT -->
<useIncrementalCompilation>false</useIncrementalCompilation>
</configuration>
</plugin>
I try to use aspectj maven plugin for compile project with aspectj compiler and then I try to package classes into "war" file. Unfortunately, it doesn't work with following configuration (pom.xml):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>com.liferay.maven.plugins</groupId>
<artifactId>liferay-maven-plugin</artifactId>
<version>${liferay.maven.plugin.version}</version>
<executions>
<execution>
<phase>generate-sources</phase>
</execution>
</executions>
<configuration>
<autoDeployDir>${liferay.auto.deploy.dir}</autoDeployDir>
<appServerDeployDir>${liferay.app.server.deploy.dir}</appServerDeployDir>
<appServerLibGlobalDir>${liferay.app.server.lib.global.dir}</appServerLibGlobalDir>
<appServerPortalDir>${liferay.app.server.portal.dir}</appServerPortalDir>
<liferayVersion>${liferay.version}</liferayVersion>
<pluginType>portlet</pluginType>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.7</source>
<target>1.7</target>
<showWarnings>true</showWarnings>
<failOnError>true</failOnError>
</configuration>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilationLevel>1.7</compilationLevel>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.4</version>
<type>jar</type>
</dependency>
After mvn clean install I see following exceptions:
[INFO] --- aspectj-maven-plugin:1.7:compile (default) # tvbs-portlet ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[ERROR] Missing message: configure.incompatibleComplianceForSource in: org.aspectj.ajdt.ajc.messages
<unknown source file>:<no line information>
[ERROR] no sources specified
<unknown source file>:<no line information>
[ERROR] AspectJ Compiler 1.8.2
Usage: <options> <source file | #argfile>..
AspectJ-specific options:
-inpath <list> use classes in dirs and jars/zips in <list> as source
Could anybody suggest me some solution?
It seems like a known issue http://jira.codehaus.org/browse/MASPECTJ-125
You can fix it by adding the following to your pom file.
<complianceLevel>1.6</complianceLevel>
Update: While the things I said about AspectJ Maven configuration in this answer are all correct, the root cause of the concrete problem at hand - bad Maven dependency management - is described in my other answer. It would be better if that one was the accepted answer and not this one.
User codelion's hint makes sense, please change your <compilationLevel> tag (typo?) - to <complianceLevel>.
There is no need to downgrade to plugin version 1.6, you can keep 1.7.
There is also no need to specify the configuration again within the <execution> section, the one at plugin level is enough.
Please note that the default AspectJ version in plugin 1.7 is 1.8.2, so maybe your runtime dependency on 1.7.4 works, but if I were you I would upgrade that one too, optimally in sync with the plugin version. It is no hard requirement, but I think it makes sense.
Maybe you even want to upgrade to the current version AspectJ 1.8.4, in the plugin as well as the runtime. This can also be achieved by adding a dependency to the desired aspectjtools version to the plugin configuration:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.source-target.version>1.8</java.source-target.version>
<aspectj.version>1.8.4</aspectj.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
<source>${java.source-target.version}</source>
<target>${java.source-target.version}</target>
<Xlint>ignore</Xlint>
<complianceLevel>${java.source-target.version}</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<!-- IMPORTANT -->
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
</dependencies>
Having looked at your Maven project https://github.com/dmitrievanthony/test-aspectj I found out that
the problem is totally unrelated to AspectJ Maven Plugin,
the same compilation errors also occur in Maven Compiler Plugin and
that the root cause of your problem is simply bad dependency management.
Here is a screenshot (full size here) from IntelliJ IDEA's "find class":
As you can see, class LockModeType is found in 3 (three!) dependencies, one of which contains a version of the class which does not contain the expected enum values. Your code compiles if you remove this dependency.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
<version>1.0.2.GA</version>
</dependency>
Maybe you should clean up your dependencies. You can use the Maven Dependency Plugin with goals like dependency:analyze and dependency:tree for that purpose.
It will be work after change plugin configuration to following:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.6</version>
<configuration>
<complianceLevel>1.7</complianceLevel>
<source>1.7</source>
<target>1.7</target>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<phase>process-sources</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<complianceLevel>1.7</complianceLevel>
<source>1.7</source>
<target>1.7</target>
</configuration>
</execution>
</executions>
</plugin>
But after this I get a lot of different compilation errors:
[ERROR] Failed to execute goal org.codehaus.mojo:aspectj-maven-plugin:1.6:compile (default) on project tvbs-portlet: Compiler errors:
[ERROR] error at Entitle.class, entitleId, LockModeType.PESSIMISTIC_WRITE);
[ERROR]
[ERROR] /Users/<...>/ejb/BillingEJB.java:43:0::0 PESSIMISTIC_WRITE cannot be resolved or is not a field
[ERROR] error at .createQuery("select e from Entitle e " +
[ERROR]
[ERROR] /Users/<...>/ejb/EntitleEJB.java:62:0::0 The method createQuery(String) in the type EntityManager is not applicable for the arguments (String, Class<Entitle>)
[ERROR] error at return entityManager.createQuery(
[ERROR] ^^
Can cause is incorrect aspectj plugin parameters?
make sure the modules has source code,like *.java etc.
when i compile CAS on version 4.0.6 it happens this error, I found the cas-server-uber-webapp doesn't has any source code in src folder. just remove the module from parent pom.xml.
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?
UPDATE: here is my maven-compiler-plugin configuration:
<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>
I work on a multi-project application that I build with Maven. We decided to add AspectJ so I added the following code to pom.xml in the top level project: (from the official documentation)
<project>
...
<dependencies>
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.7.3</version>
</dependency>
...
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<goals>
<goal>compile</goal> <!-- use this goal to weave all your main classes -->
<goal>test-compile</goal> <!-- use this goal to weave all your test classes -->
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
<build>
...
</project>
and the following fragments to each subordinate projects:
</project>
...
<build>
....
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
...
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
....
</dependencies>
...
</project>
Somehow this modification has overridden the Java version I use. If I run build I get multiple errors like this:
Syntax error, annotations are only available if source level is 1.5 or greater
That gives me the suspicion that my Java version (originally 1.6) was somehow reverted to 1.4. I did nothing - at least not knowingly - that could influence the Java version, so I suspect that the above mentioned AspectJ related code is responsible for the change.
My question is how can AspectJ change the Java version and what should I do to fix this problem. Or do I misunderstand something completely and am I on the wrong track?
I think the problem is with the default source, target and complianceLevel settings of the aspectj-maven-plugin (according to the documentation linked previously, 1.4, 1.2 and 1.4 respectively). You should set these explicitly in your parent pom:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<!-- new configuration is here -->
<configuration>
<complianceLevel>1.6</complianceLevel>
<source>1.6</source>
<target>1.6</target>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
<build>
I was missing
<complianceLevel>${java.level}</complianceLevel>
in my pom.xml
If you don't have define the version, the compiler plugin assumes that your Java source conforms to Java 1.3 and that you are targeting a Java 1.1 JVM.
Maybe, you should define it:
http://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html
You can find last versions of dependecy and plugin for aspectj.
I was missing the java version with jdk version at the top of my pom properties.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version> <!-- 1.5 dint work for me -->
<dependencies>
<!-- You must use Maven 2.0.9 or above or these are ignored (see MNG-2972) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>process-sources</phase> <!-- or any phase before compile -->
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<outxml>true</outxml>
<source>${jdk.version}</source> <!-- I was missing this -->
<target>${jdk.version}</target> <!-- jdk.version property -->
</configuration>
</plugin>
and at the top of my pom.xml I had set jdk.version property like,
<properties>
<jdk.version>1.7</jdk.version>
</properties>