英文:
Mockito Mock a static void method with Mockito.mockStatic()
问题
我正在使用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);
}
但我无法成功模拟静态void方法,比如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方法?如果可能的话,正确的语法是什么?
英文:
I'm using Spring Boot and in one of my unit test, I need to mock the Files.delete(somePath)
function. Which is a static void method.
I know that with Mockito it is possible to mock void method:
doNothing().when(MyClass.class).myVoidMethod()
And since July 10th 2020, it is possible to mock static method:
try (MockedStatic<MyStaticClass> mockedStaticClass = Mockito.mockStatic(MyStaticClass.class)) {
mockedStaticClass.when(MyStaticClass::giveMeANumber).thenReturn(1L);
assertThat(MyStaticClass.giveMeANumber()).isEqualTo(1L);
}
But I can't manage to mock a static void mehtod such as Files.delete(somePath)
.
This is my pom.xml file (only test related dependencies):
<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>
Is there a way to mock static void methods without using PowerMockito ?
If it is possible, what is the correct syntax to do so ?
答案1
得分: 18
通常情况下,模拟静态调用是最后的手段,不应作为默认方法。
例如,为了测试与文件系统交互的代码,有更好的方法。例如,根据junit
版本,可以使用TemporaryFolder
规则或者@TempDir
注解。
还请注意,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及以上版本可用,请检查您使用的版本是否正确。 -
代码片段故意展示了两种方法:
@TempDir
和Mockito.mockStatic
。当同时运行这两个测试时,您会注意到Mockito.mockStatic
的速度要慢得多。例如,在我的系统上,使用Mockito.mockStatic
运行时间大约为 900 毫秒,而使用@TempDir
则为 10 毫秒。
英文:
In general mocking static calls is the last resort, that is not supposed to be used as default approach.
For example, for testing the code, that works with file system, there are better means. E.g. depending on the junit
version either use TemporaryFolder
rule or @TempDir
annotation.
Also, please note, that Mockito.mockStatic
might significantly slow down your tests (e.g. look at the notes below).
Having said the caution above, find the snippet below, that shows how to test, that file got removed.
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));
}
}
}
Notes:
-
Mockito.mockStatic
is available in Mockito 3.4 and above, so check you're using correct version. -
The snippet deliberatly shows two approaches:
@TempDir
andMockito.mockStatic
. When run both tests you'll notice thatMockito.mockStatic
is much slower. E.g. on my system test withMockito.mockStatic
runs around 900 msec vs 10 msec for@TempDir
.
答案2
得分: 0
使用mockStatic
,然后在返回的实例中指定模拟对象。
try (MockedStatic<Files> mockFiles = Mockito.mockStatic(Files.class)) {
mockFiles.when(() -> Files.delete(anyString()))
.then(invocationOnMock -> null);
}
英文:
Use mockStatic and then specify the mock in the returned instance.
try (MockedStatic<Files> mockFiles = Mockito.mockStatic(Files.class)) {
mockFiles.when(() -> Files.delete(anyString()))
.then(invocationOnMock -> null);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论