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

标签 java spring spring-boot unit-testing mockito

我正在使用 Spring Boot 并且在我的一个单元测试中,我需要模拟 Files.delete(somePath)功能。这是一个静态void方法。
我知道使用 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 的情况下模拟静态 void 方法?
如果可能,这样做的正确语法是什么?

最佳答案

通常,模拟静态调用是最后的手段,不应将其用作默认方法。
例如,对于测试文件系统的代码,有更好的方法。例如。取决于 junit版本要么使用 TemporaryFolder rule @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));
        }
    }
}
备注:
  • Mockito.mockStatic在 Mockito 3.4 及更高版本中可用,因此请检查您使用的是正确的版本。
  • 该片段特意展示了两种方法:@TempDirMockito.mockStatic .运行这两个测试时,您会注意到 Mockito.mockStatic慢得多。例如。在我的系统测试中 Mockito.mockStatic运行大约 900 毫秒 vs 10 毫秒 @TempDir .
  • 关于java - Mockito 使用 Mockito.mockStatic() 模拟静态 void 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64463733/

    相关文章:

    java - Angular代码不会通过将id传递给JAVA(使用Spring)来删除json

    java - Spring Dao和Dao patter在异常处理上的冲突

    spring 接口(interface)作为@ModelAttribute 参数

    java - Spring Boot 验证该字段是字符串类型

    hibernate - Spring 在事务结束时启动不需要的 SQL 更新

    java - 泛型和 ClassCastException : why do I get this exception, 我该如何处理 "work around"呢?

    java - 简单的 Java 扫描器代码不起作用

    java - 如何在 spring-boot 1.5.10 中升级 JUnit-5?

    java - Spring WebFlow,我找不到流程之外的文件路径?

    mysql - 如何使用外键将数据插入多个表 Spring Boot Java MySQL