java – 从PowerMock 1.6.2升级到1.6.6以集成JaCoCo 0.7.8后,“whenNew”调用结果为空值

我有一个较大的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.

最佳答案 首先是关于你的陈述

The latest version of JaCoCo, 0.7.8, requires 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 works only with PowerMock version 1.6.6 and upper.

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

Change log 1.6.6 (2016-11-04)

  • Fixed #645 jacoco offline instrumentation incompatibility with powermock byte-code manipulation when using @SuppressStaticInitializationFor

即只针对一个特定情况进行修复.在其他情况下,早期版本的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 /主/ JAVA /组织/示例/ 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 /主/ JAVA /组织/示例/ 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 /主/ JAVA /组织/示例/ Example.java:

package org.example;

public class Example {

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

}

的src /测试/ JAVA /组织/示例/ 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的集成.

点赞