【问题标题】:After upgrading from PowerMock 1.6.2 to 1.6.6 to integrate JaCoCo 0.7.8, a "whenNew" call result in a null value从 PowerMock 1.6.2 升级到 1.6.6 以集成 JaCoCo 0.7.8 后,“whenNew”调用导致空值
【发布时间】:2017-01-23 21:19:35
【问题描述】:

我有一个较大的 Maven 多项目构建,单元测试主要使用 PowerMock,版本为 1.6.2。我决定集成 JaCoCo,这样我们就可以开始发布我们的代码覆盖率指标了。 JaCoCo 的最新版本 0.7.8 需要 PowerMock 1.6.6,所以我升级了我的版本。

我现在看到与“whenNew”调用有关的一些错误行为,该调用在代码库中的整个测试中重复出现变化。

有问题的“whenNew()”调用如下所示:

PowerMockito.whenNew(BlahBlah.class)
            .withArguments(any(SomeClass.class))
            .thenReturn(blahBlahInstance);

使用 PowerMock 1.6.2,这一切正常。当我升级到 1.6.6 时,为了完成这项工作,我必须进行两项更改,一项可以接受但很烦人(因为我不知道为什么需要它),另一项确实不能接受。

可接受的更改是类顶部的“@PrepareForTest”注释。在 PowerMock 1.6.2 中,这用于仅列出调用“new BlahBlah(...)”的类,并且工作正常。为了使它工作(除了下一个更改),我还必须将“BlahBlah.class”添加到该列表中。我可以接受这一点,但如果我对该列表的确切内容有一个明确的方向,那将真的很有帮助。

第二个不可接受的更改是我必须将“.withArguments(any(SomeClass.class))”更改为“.withAnyArguments()”。我也试过“withArguments(anyObject())”,也没有成功。

更新

请注意,我使用的是 mockito-core 版本 1.10.19。我从https://github.com/powermock/powermock/wiki/MockitoUsage#supported-versions 看到,PowerMock 1.6.6 (1.6.2+) 支持该版本的 mockito-core。

【问题讨论】:

  • 你得到解决方案了吗
  • 是的。如果您仍有问题,请发布单独的问题。

标签: java maven powermock jacoco powermockito


【解决方案1】:

首先是关于你的陈述

JaCoCo 的最新版本 0.7.8 需要 PowerMock 1.6.6

JaCoCo 不需要 PowerMock,而且 JaCoCo 0.7.8 中的 PowerMock 并没有什么特别之处。截至今天,0.7.8 只是 JaCoCo 的最新发布版本。

我猜你的陈述是来自阅读 https://github.com/powermock/powermock/wiki/Code-coverage-with-JaCoCo 的一种误解,其中指出

JaCoCo Offline Instrumentation 仅适用于 PowerMock 1.6.6 及更高版本。

根据https://github.com/powermock/powermock/blob/master/changelog.txt

更改日志 1.6.6 (2016-11-04)

  • 修复了 #645 jacoco 离线检测在使用 @SuppressStaticInitializationFor 时与 powermock 字节码操作不兼容的问题

即仅针对一种特定情况进行了修复。在其他情况下,早期版本的 PowerMock 已经使用离线工具与早期版本的 JaCoCo 一起工作。

然后根据您对 PowerMock 升级到 1.6.6 后的状态描述,但在其他更改之前,尝试创建一个 Minimal, Complete, and Verifiable example

pom.xml:

<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>org.example</groupId>
  <artifactId>example</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>

    <powermock.version>1.6.6</powermock.version>
    <jacoco.version>0.7.8</jacoco.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</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>org.jacoco</groupId>
      <artifactId>org.jacoco.agent</artifactId>
      <classifier>runtime</classifier>
      <version>${jacoco.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <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>${jacoco.version}</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>
            <phase>package</phase>
            <goals>
              <goal>report</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

src/main/java/org/example/BlahBlah.java:

package org.example;

public class BlahBlah {

  private final SomeClass c;

  public BlahBlah(SomeClass c) {
    this.c = c;
  }

  public String run() {
    return c.toString();
  }
}

src/main/java/org/example/SomeClass.java:

package org.example;

public class SomeClass {

  private final String s;

  public SomeClass(String s) {
    this.s = s;
  }

  @Override
  public String toString() {
    return s;
  }

}

src/main/java/org/example/Example.java:

package org.example;

public class Example {

  public String fun() {
    return new BlahBlah(new SomeClass("Hello World")).run();
  }

}

src/test/java/org/example/ExampleTest.java:

package org.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;

@PrepareForTest({Example.class})
@RunWith(PowerMockRunner.class)
public class ExampleTest {

  @Test
  public void test() throws Exception {
    BlahBlah e = new BlahBlah(new SomeClass("Hello PowerMock"));
    PowerMockito.whenNew(BlahBlah.class)
      .withArguments(any(SomeClass.class))
      .thenReturn(e);
    assertEquals("Hello PowerMock", new Example().fun());
  }

}

mvn clean verify

工作得很好。因此,您的描述中应该还遗漏了一些其他内容来真正重现您的情况。希望这会有所帮助,至少可以在此基础上构建更好的复制器。

另外:尝试将 JaCoCo 的集成过程与 PowerMock 的升级分离——也许只是这个升级有问题,而不是 JaCoCo 的集成。

【讨论】:

  • 老实说,在 PowerMock 1.6.6 之前,由于我们在 JaCoCo 问题中讨论的问题,所有添加到 @PrepareForTest 的类的覆盖率为零。但这也是@SuppressStaticInitializationFor、JaCoCo 和 TestNG 引发异常时的问题。
【解决方案2】:

对于我的具体问题,事实证明,这不起作用的唯一地方是实际的“SomeClass”参数为空,它与“any(SomeClass.class)”不匹配。在这些情况下,我不得不将子句更改为“withAnyArguments()”。

【讨论】:

    猜你喜欢
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 2014-03-29
    • 1970-01-01
    • 2011-10-08
    • 2019-02-06
    • 2020-07-10
    • 1970-01-01
    相关资源
    最近更新 更多