【问题标题】:NotAMockException exception when trying to verify a static method with Powermockito尝试使用 Powermockito 验证静态方法时出现 NotAMockException 异常
【发布时间】:2022-03-14 21:15:13
【问题描述】:

我使用PowerMock 来测试文档中提到的静态方法。

据我所知,可能存在错误,但我不确定:

Static mocking broken for Mockito >= 2.26.1

...

我尝试了以下页面中提到的解决方法,但它并不能解决问题,并且其中一些已过时而无法适用。

NotAMockException when trying to verify a static method

verifyStatic get NotAMockExcption from mockito

但是,我得到 “传递给 verify() 的参数是 Class 类型,不是模拟!” 错误。这是我正在测试的服务方法和测试方法:

服务:

// I want to test this method
 public CommandDTO create(EmployeeRequest request) {
    // ...

    log();
    return CommandDTO.builder().uuid(employee.getUuid()).build();
}


private void log() {
    LoggingUtils.info("Created...");
}

测试:

@RunWith(PowerMockRunner.class)
@PrepareForTest(LoggingUtils.class)
public class EMployeeServiceImplTest {

    @Test
    public void unit_test() {

        // ...

        PowerMockito.mockStatic(LoggingUtils.class);

        employeeService.create(request);

        PowerMockito.verifyStatic(LoggingUtils.class); // throws error

        LoggingUtils.info(any());
    }
}

这里是库和版本:

pom.xml:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.4.6</version>
    <scope>test</scope>
</dependency>

【问题讨论】:

  • 您使用什么版本的 PowerMock 和 Mockito?
  • 你用的是什么java版本?
  • 我使用 Java 11...

标签: java spring-boot unit-testing mockito powermock


【解决方案1】:

既然你在另一条评论中问过,这是我过去用来防止需要静态模拟的一种模式:

假设我们有一个静态方法...

public class SomeClass {
  public static String doSomething(int x) { ... }
}

现在想象我们的代码是这样使用它的......

public class MyClass {
  public void someMethod() {
    String xyz = SomeClass.doSomething(123);
    ...
  }
}

如果我们现在需要模拟 SomeStaticClass.doSomething(123) 调用,我们需要静态模拟。

另一种选择是委托人:

public class MyDelegator {
  public String doSomething(int x) { 
    return SomeClass.doSomething(x);
  } 
}

现在您可以在课堂上使用它:

public class MyClass {
  private final MyDelegator myDelegator;

  public MyClass(MyDelegator myDelegator) { this.myDelegator = myDelegator; }

  public void someMethod() {
    String xyz = myDelegator.doSomething(123);
    ...
  }
}

瞧,您可以简单地模拟 MyDelegator 对象,而不必担心原始实现是静态调用。

当然,这并不能解决底层代码的异味,但它可以帮助您在无法重构静态代码本身的情况下解决它。

【讨论】:

    【解决方案2】:

    让我建议完全不同的方法,因为我看到您已经使用 Mockito 版本 3.4.6 。 从Mockito &gt;= 3.4.0 开始,您可以直接模拟静态方法。这意味着您可以完全摆脱 PowerMock 依赖。
    此外,AFAIK PowerMock 不支持 JUnit5。此解决方案将允许您将 JUnit 测试框架升级到版本 5,而我也强烈推荐这一点。

    使用 Mockito 的静态模拟确实需要您使用 mockito-inline 依赖于 mockito-core 但是,因为 mockito-inline 依赖于 mockito-core,Maven 也会下载 mockito-core 包。请注意,Mockito 文档指出,在未来的某个时候,他们可能会在取消所有这些包时废除这个包 核心包的“实验性”功能。
    除此之外,您还应该将@RunWith(PowerMockRunner.class) 替换为@RunWith(MockitoJUnitRunner.class)

    这就是你使用它的方式。

    您可以像这样使用自动调用 close 的 try-with-resources 语句定义每个测试方法的模拟

        try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
            filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
         
            // Call logic
        }
    

    或者您可以在 @Before 方法中为所有测试定义它,因为您使用的是 jUnit4。

        private MockedStatic<Files> filesMock;
    
        @Before
        public void init() {
            filesMock = org.mockito.Mockito.mockStatic(Files.class);
        }
    
        @After
        public void teardown() {
            filesMock.close();
        }
        
        @Test
        void test() {
            filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
        }
    

    https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#mockito-inline https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks

    【讨论】:

    • 非常感谢您的详细解释,投了赞成票。我同意你的观点,但在 PowerMock 之前,我已经尝试过使用 MockedStatic 并且它的 verify() 方法也无法正常工作。因为我尝试了调用次数,并且当我不调用静态方法时,它不计算已经调用静态方法的服务方法调用。当我在 try 块中调用静态方法时,它与静态方法调用一样多。这清楚地表明它没有按预期进行验证。在您的示例中,有 when() 方法,但我对 when 没有任何问题。
    猜你喜欢
    • 2020-03-04
    • 2018-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多