【问题标题】:Mockito Mock a static void method with Mockito.mockStatic()Mockito 使用 Mockito.mockStatic() 模拟静态 void 方法
【发布时间】:2021-02-04 09:04:06
【问题描述】:

我正在使用 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) 等静态 void 方法。

这是我的 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 方法?
如果可能,这样做的正确语法是什么?

【问题讨论】:

  • 你添加 mockito-inline 作为依赖了吗?
  • 是的,我做了,我将编辑我的问题以添加我的 POM.xml 文件。

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


【解决方案1】:

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

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

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

说了上面的警告,找到下面的sn-p,它显示了如何测试,那个文件被删除了。

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. sn-p 特意展示了两种方法:@TempDirMockito.mockStatic。运行这两个测试时,您会注意到 Mockito.mockStatic 的速度要慢得多。例如。在我使用Mockito.mockStatic 进行的系统测试中,@TempDir 运行大约 900 毫秒,而@TempDir 则为 10 毫秒。

【讨论】:

  • 非常感谢您的回答!我知道模拟静态方法不是一个好习惯,但我不知道它这么慢。感谢您解释正确的方法,我会实施它。
猜你喜欢
  • 2014-08-30
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多