无法让Jacoco使用离线工具与Powermockito合作

问题描述 投票:30回答:11

鉴于Jacoco在“动态”工具时不能很好地与PowerMockito配合使用,我一直在尝试配置离线工具,希望这能为我提供适用于使用PowerMockito的类的单元测试覆盖率。

我已经将我的pom设置如下,但我的测试课程仍然保持0%的覆盖率。任何帮助都非常感激,因为它让我慢慢疯狂!

<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>

这是我的课程:

public class Utils {

    private Utils() {

    }

    public static String say(String s) {
        return "hello:"+s;
    }
}

这是我的测试:

@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"));
    }

}

我运行mvn clean install生成jacoco.exe

覆盖率报告(使用ant脚本从jacoco.exec生成): -

java powermock jacoco
11个回答
15
投票

这个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>

请参阅this链接。


0
投票

Code Coverage with JaCoCo解释了原因

使用JaCoCo的最简单方法是使用JaCoCo Java Agent进行即时检测。在这种情况下,一个类在被加载时被修改。您可以使用JaCoCo代理运行应用程序,并计算代码覆盖率。这种方式被Eclemma和Intellij Idea使用。但是有一个大问题。 PowerMock乐器类也。 Javassist用于修改类。主要问题是Javassist从磁盘读取类,所有JaCoCo更改都消失了。因此,类Power的零代码覆盖率由PowerMock类加载器加载。

我们将用ByteBuddy(#727)取代Javassist,它应该有助于解决这个老问题。但是现在没有办法使用带有JaCoCo On-the-fly仪器的PowerMock。并没有解决方法来获得IDE中的代码覆盖率。

JaCoCo Offline Instrumentation可以解决这个问题。 Offline Instrumentation的样本解决了我的问题。


0
投票

报告是正确的。当您模拟调用方法“说”时发生的情况时,提供的测试将导致无法覆盖。永远不应该模拟“测试中的实例/类”,只针对测试主题的依赖关系和环境做这件事。

在这种情况下:测试永远不会到达代码return "hello:"+s;,并且不会调用Utils的构造函数。没有显示覆盖范围,因为根本没有这些线的测试覆盖范围。

尽管如此,将JaCoCo和PowerMock结合使用并非易事。我目前正在寻找如何让它运行。也许您提供的测试只是写得不好而且JaCoCo已经在应用了吗?


8
投票

我看到了同样的行为,虽然在GitHub问题上跟随线程之后,似乎在1.6.5中修复了,这对我来说是正确的。

希望这会在以后让人头疼:)。

工作配置:

  • jacoco-maven-plugin 0.7.7.201606060606
  • powermock 1.6.5

我没有使用离线仪器。


1
投票

我也面临同样的问题。我能够部分生成报告。我已将这两个标签用于我的测试用例@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>

以下是我在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}被设置为属性

<properties>
    <argLine>-noverify -Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=512m</argLine>
</properties>

并将我的powermock版本从1.5.5升级到1.6.5。最后,我可以在我的测试用例中使用以下标记的类看到我的报告生成@RunWith(PowerMockRunner.class)@PrepareForTest({})


1
投票

对我来说,这个Offline Instrumentation样本效果很好。

但在我的情况下,有一个更简单的解决方案:只是在声明之前不要在@PrepareForTest({})注释中包含测试类。


1
投票

我使用PowerMock的javaagent使它工作。看到这里:https://github.com/powermock/powermock/wiki/PowerMockAgent

删除@RunWith注释,按照上面的链接中所述放置PowerMockRule。把它公之于众。

将以下行放在maven-surefire-plugin配置中:

-javaagent:${org.powermock:powermock-module-javaagent:jar}

(使用此处描述的技术: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> 

0
投票

我最终使用离线仪器和Jacoco(类似于你所做的)与sonar一起使用,我能够从中得到覆盖率数字。


0
投票

我使用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>

0
投票

我和JaCoCo On-the-fly和PowerMock有同样的问题。每次都会生成0%的代码覆盖率

发现JaCoCo版本0.7.7.201606060606和PowerMock版本1.6.2兼容并且代码覆盖成功生成。


0
投票

使用下面的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>
© www.soinside.com 2019 - 2024. All rights reserved.