使用 MockStatic 的离线 Jacoco 导致重新检测异常

Offline Jacoco using MockStatic cause re-instrumentation exception

我运行正在使用 PowerMock 1.6.4 和所有最新版本(尽管是 JUnit 4.11)。

现在我遇到了一个我想不通的问题...

我注意到 PowerMockito.mockStatic(Foo.class) ...所有测试都因仪器问题而失败。

我有另一个测试 class 测试 Foo 的另一个成员函数。这个测试 class 工作正常,但是一旦我引入 mockStatic,测试 class 就会因检测失败而失败。

有没有人看到过这种失败并知道任何解决方法?我无法更改静态成员变量。

我终于弄清楚了我认为的问题所在。 Jacoco 检测将数据注入字节码,PowerMock 在尝试模拟静态时也是如此。这会造成严重破坏,因为它们相互踩踏,而且由于它们相互干扰,你会得到非常奇怪的行为。我在代码中得到了一堆不应抛出 NPE 的 NPE。

简单的解决方案是重构不必要的静态,并且知道如果您计划使用静态来控制数据流,如果您计划使用 Jacoco 进行覆盖,可能应该重新考虑测试架构。

您仍然可以 运行 Jacoco 对静态进行检测,但不能同时模拟静态;至少不像 PowerMock with Mockito 那样。我不确定 EasyMock 是否会导致不同的行为,所以 ymmv.

我遇到了类似的问题,但我相信有另一种解决方案,而不是必须重构静力学。我在一个 maven pom 文件中做了这个,但我会解释发生了什么。 Jacoco 确实将数据注入到您的字节代码中。是的,Powermock 使用自定义字节加载器,而 Jacoco 讨厌它。所以这是解决它的解决方案。

在您的 Jacoco 执行中,您需要 Jacoco 为您的测试使用默认检测。 (您可以指定 powermock 测试或只包括它以任何一种方式工作的所有测试)。下面是对默认工具的解释:Offline-instrumentation with Jacoco

然后您必须执行测试的还原步骤。现在是有趣的部分,您必须 运行 正常的 Jacoco Prepare Agent 步骤,同时排除所有在默认检测中 运行 的测试。 (如果你不这样做,你会收到一堆警告,比如 xTest 已经存在 JaCoCo 执行数据)

这将解决您的问题,您无需重构静态方法。虽然如果它们是不必要的,你可能还是应该把它们拿出来 ;)

 <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <configuration>
                    <append>true</append>
                </configuration>
                <executions>
                    <execution>
                        <id>default-instrument</id>
                        <goals>
                            <goal>instrument</goal>
                        </goals>
                        <configuration>
                            <includes>
                                <include>**/*test*</include>
                            </includes>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-restore-instrumented-classes</id>
                        <goals>
                            <goal>restore-instrumented-classes</goal>
                        </goals>
                        <configuration>
                            <includes>
                                <include>**/*test*</include>
                            </includes>
                        </configuration>
                    </execution>
                    <execution>
                        <id>Prepare-Jacoco</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <excludes>
                                <exclude>**/*test*</exclude>
                            </excludes>
                        </configuration>
                    </execution>
                </executions>
            </plugin>