关于如何正确在测试用例中mock静态方法的问题
文章目录
- 情况一:希望在测试用例中直接执行静态方法的逻辑
- 情况二:不希望在测试用例中执行静态方法的逻辑
- 插桩方法
- 坑1: 报错SubclassByteBuddyMockMaker
- 原因与解决方案
- 坑2:报错 the existing static mock registration must be deregistered
- 原因与解决方案
关于如何正确在测试用例中mock 静态方法的问题
情况一:希望在测试用例中直接执行静态方法的逻辑
// 比较简单,使用注解@Spy即可
@Spy
private DateUtils dateUtils;
情况二:不希望在测试用例中执行静态方法的逻辑
而是希望通过mock来模拟执行,比如静态方法中是关于某些客户端的操作,直接mock就行了。
插桩方法
try (MockedStatic<FeiShuUtil> feiShuUtilMockedStatic = Mockito.mockStatic(FeiShuUtil.class)) {
feiShuUtilMockedStatic.when(() -> FeiShuUtil.getFeiShuUsersByPhones(any(), any(), any())).thenReturn(List.of(new UserContactInfo()));
// Act
UrgentMessageSendDto sendDto = getUrgentMessageSendDto();
ApiResultDto<String> result = messageSendService.sendUrgentPhoneMessage(sendDto);
// Assert
assertThat(result.getEr()).isEqualTo(ApiErrorCode.SERVER_ERROR.getCode());
} // 这里静态模拟会被自动取消注册
坑1: 报错SubclassByteBuddyMockMaker
org.mockito.exceptions.base.MockitoException:
The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks
Mockito's inline mock maker supports static mocks based on the Instrumentation API.
You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'.
Note that Mockito's inline mock maker is not supported on Android.
原因与解决方案
原因:意味着当前使用的 Mockito 版本和配置不支持静态方法的模拟。这通常发生在使用较旧版本的 Mockito 或者没有正确设置以启用对静态方法模拟的支持时。
解决方法:添加依赖
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.12.4</version>
<scope>test</scope>
</dependency>
坑2:报错 the existing static mock registration must be deregistered
在执行单次测试用例的时候没有报错,但是一到集成测试,会测试一系列的测试用例,会有报错:
org.mockito.exceptions.base.MockitoException:
For com.nimbus.messagecenter.util.FeiShuUtil, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
原因与解决方案
原因:插桩方法不对,,写法如下,没有通过try包起来
这个错误信息表明在当前线程中已经注册了一个针对 FeiShuUtil 类的静态方法的 Mockito 模拟(mock),并且您正尝试再次创建一个新的模拟,这违反了 Mockito 的规则。Mockito 不允许在同一线程中多次注册对同一类的静态方法的模拟。
当需要模拟静态方法时,通常会使用 Mockito.mockStatic() 方法来创建一个静态模拟。该调用返回一个 try-with-resources 语句或类似的作用域管理器,它会在作用域结束时自动取消注册静态模拟。如果您没有正确地关闭这个作用域,或者在一个测试方法中多次尝试创建静态模拟,就会遇到上述错误。
MockedStatic<FeiShuUtil> feiShuUtilMockedStatic = Mockito.mockStatic(FeiShuUtil.class)
feiShuUtilMockedStatic.when(() -> FeiShuUtil.getFeiShuUsersByPhones(any(), any(), any())).thenReturn(List.of(new UserContactInfo()));
// Act
UrgentMessageSendDto sendDto = getUrgentMessageSendDto();
ApiResultDto<String> result = messageSendService.sendUrgentPhoneMessage(sendDto);
// Assert
assertThat(result.getEr()).isEqualTo(ApiErrorCode.SERVER_ERROR.getCode());
}