Java 无法使用离线仪器让 Jacoco 与 Powermockito 一起工作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23983740/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unable to get Jacoco to work with Powermockito using offline instrumentation
提问by MandyW
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.
鉴于 Jacoco 在“动态”检测时不能很好地与 PowerMockito 配合使用,我一直在尝试配置离线检测,希望这将为使用 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!
我已经按如下方式设置了我的 pom,但我的测试类仍然得到零%的覆盖率。任何帮助都非常感谢,因为它让我慢慢发疯!
<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
我运行 mvn clean install 生成 jacoco.exe
Coverage report (generated from jacoco.exec using an ant script ):-
覆盖率报告(使用 ant 脚本从 jacoco.exec 生成):-
回答by gce
This pom worked for me:
这个 pom 对我有用:
<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 thislink.
请参阅此链接。
回答by Ashwin Krishnamurthy
回答by akhanna3
I made it work using the javaagent of PowerMock. see here: https://github.com/powermock/powermock/wiki/PowerMockAgent
我使用 PowerMock 的 javaagent 使它工作。见这里:https: //github.com/powermock/powermock/wiki/PowerMockAgent
Remove the @RunWith
annotations, put the PowerMockRuleas described in the link above. Make it public.
删除@RunWith
注释,按照上面链接中的描述放置PowerMockRule。公开。
Put the following line in the maven-surefire-plugin configuration:
将以下行放在 maven-surefire-plugin 配置中:
-javaagent:${org.powermock:powermock-module-javaagent:jar}
(used the technique described here : Can I use the path to a Maven dependency as a property?)
(使用此处描述的技术:我可以使用 Maven 依赖项的路径作为属性吗?)
<?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>
回答by FatalError
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.
我看到了相同的行为,但在关注 GitHub 问题上的线程后,它似乎在 1.6.5 中得到了修复,这对我来说是正确的。
Hopefully this will save someone a headache later :).
希望这会在以后让某人头疼:)。
Working configuration with:
工作配置:
- jacoco-maven-plugin 0.7.7.201606060606
- powermock 1.6.5
- jacoco-maven-plugin 0.7.7.201606060606
- 电源模拟 1.6.5
I am not using offline instrumentation.
我没有使用离线仪器。
回答by Avinash Reddy
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.xmlentry
我也面临同样的问题。我能够部分生成报告。我在我的测试用例@RunWith(PowerMockRunner.class) @PrepareForTest({}) 中使用了这两个标签。并且没有为我使用上述标签的测试用例生成报告。但是对于其中一个测试用例,只有这个标签@RunWith(PowerMockRunner.class)。不知何故,该报告正在为该案例生成。而且我从未使用过离线仪器。当我尝试使用离线检测时,我收到错误消息,指出该类已被检测。我尝试了各种场景并遵循了各种链接,但无法生成报告。最后根据上面的评论,我将我的 powermock 版本从 1.5.5 升级到 1.6.5,并且我能够生成报告。以下是我的pom.xml入口
<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
以下是我在pom .xml 中的 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
@{argLine} 被设置为一个属性
<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({})
并将我的 powermock 版本从 1.5.5 升级到 1.6.5。最后,我可以看到我在测试用例中使用以下标签的类的报告生成 @RunWith(PowerMockRunner.class) @PrepareForTest({})
回答by Ananth
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:
我使用了 Jacoco 离线仪器,并在执行测试后在“恢复仪器类”目标的帮助下恢复了原始类。我的 JaCoCo 配置如下所示:
<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>
回答by Zilvinas
I had same issue with JaCoCo On-the-fly and PowerMock. 0% code coverage was generated every time
我在 JaCoCo On-the-fly 和 PowerMock 上遇到了同样的问题。每次都生成 0% 的代码覆盖率
Found out that JaCoCo version 0.7.7.201606060606 and PowerMock version 1.6.2 are compatible and code coverage is generated successfully.
发现JaCoCo 0.7.7.201606060606版本和PowerMock 1.6.2版本兼容,代码覆盖生成成功。
回答by Vashishtkumar Balagannavar
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
使用下面的 maven 插件代码片段,这在 jenkins 和本地都可以正常工作,并显示了 PowermockRunner 单元测试的完整代码覆盖率
<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>
回答by Andriy Boyko
For me this sample of Offline Instrumentationworks 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.
但在我的情况下,有一个更简单的解决方案:只是在声明之前不要在 @PrepareForTest({}) 注释中包含测试类。
回答by Robert11
Code Coverage with JaCoCoexplained the reason
JaCoCo 的代码覆盖率解释了原因
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 的最简单方法是使用 JaCoCo Java Agent 进行即时检测。在这种情况下,类在加载时被修改。您可以使用 JaCoCo 代理运行您的应用程序并计算代码覆盖率。Eclemma 和 Intellij Idea 使用这种方式。但是有一个大问题。PowerMock 仪器类也是。Javassist 用于修改类。主要问题是 Javassist 从磁盘读取类并且所有 JaCoCo 更改都消失了。因此,PowerMock 类加载器加载了类女巫的零代码覆盖率。
我们将用 ByteBuddy (#727) 替换 Javassist,它应该有助于解决这个老问题。但是现在没有办法将 PowerMock 与 JaCoCo On-the-fly 仪器一起使用。并且没有解决方法可以在 IDE 中获得代码覆盖率。
JaCoCo Offline Instrumentation can solve this problem. The sample of Offline Instrumentationfixed my problem .
JaCoCo Offline Instrumentation 可以解决这个问题。Offline Instrumentation的示例 解决了我的问题。