Mockito 使用 Mockito.mockStatic() 模拟静态 void 方法

Mockito Mock a static void method with Mockito.mockStatic()

我正在使用 Spring Boot,在我的一个单元测试中,我需要模拟 Files.delete(somePath) 函数。这是一个静态无效方法。

我知道使用 Mockito 可以模拟 void 方法:

doNothing().when(MyClass.class).myVoidMethod()

并且自 2020 年 7 月 10 日起,可以模拟静态方法:

try (MockedStatic<MyStaticClass> mockedStaticClass = Mockito.mockStatic(MyStaticClass.class)) {
    mockedStaticClass.when(MyStaticClass::giveMeANumber).thenReturn(1L);
    assertThat(MyStaticClass.giveMeANumber()).isEqualTo(1L);
  }

但我无法模拟静态无效方法,例如 Files.delete(somePath)

这是我的pom.xml文件(只测试相关的依赖):

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.5.15</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.5.15</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>3.5.15</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <version>2.2.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

有没有办法在不使用 PowerMockito 的情况下模拟 static void 方法?
如果可能的话,正确的语法是什么?

一般来说,模拟静态调用是最后的手段,不应用作默认方法。

例如,对于与文件系统一起工作的代码的测试,有更好的方法。例如。根据 junit 版本使用 TemporaryFolder rule or @TempDir annotation.

此外,请注意,Mockito.mockStatic 可能会显着降低您的测试速度(例如,查看下面的注释)。

说完上面的警告,找到下面的片段,它显示了如何测试,该文件已被删除。

class FileRemover {
    public static void deleteFile(Path filePath) throws IOException {
        Files.delete(filePath);
    }
}

class FileRemoverTest {

    @TempDir
    Path directory;

    @Test
    void fileIsRemovedWithTemporaryDirectory() throws IOException {
        Path fileToDelete = directory.resolve("fileToDelete");
        Files.createFile(fileToDelete);

        FileRemover.deleteFile(fileToDelete);

        assertFalse(Files.exists(fileToDelete));
    }

    @Test
    void fileIsRemovedWithMockStatic() throws IOException {
        Path fileToDelete = Paths.get("fileToDelete");
        try (MockedStatic<Files> removerMock = Mockito.mockStatic(Files.class)) {
            removerMock.when(() -> Files.delete(fileToDelete)).thenAnswer((Answer<Void>) invocation -> null);
            // alternatively
            // removerMock.when(() -> Files.delete(fileToDelete)).thenAnswer(Answers.RETURNS_DEFAULTS);

            FileRemover.deleteFile(fileToDelete);

            removerMock.verify(() -> Files.delete(fileToDelete));
        }
    }
}

备注:

  1. Mockito.mockStatic 在 Mockito 3.4 及更高版本中可用,因此请检查您使用的版本是否正确。

  2. 该片段故意显示了两种方法:@TempDirMockito.mockStatic。当 运行 两个测试时,您会注意到 Mockito.mockStatic 慢得多。例如。在我的系统测试中 Mockito.mockStatic 运行s 大约 900 毫秒 vs @TempDir.

    10 毫秒