mock静态方法指引
mockito 在3.4.0版本开始支持mock static method
文档:https://wttech.blog/blog/2020/mocking-static-methods-made-possible-in-mockito-3.4.0/
1. 升级Maven依赖
<!-- mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.6.28</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.4.0</version>
<scope>test</scope>
</dependency>
2. 使用方式
- 静态方法
public final class MysteryBox {
public static Optional<Mystery> amaze(String codeWord) {
// todo
}
}
- 待测试的类,使用了MysteryBox.amaze(String)静态方法
public class HaplessUser {
public Mystery unleashMystery(String magicSpell) {
Optional<Mystery> om = MysteryBox.amaze(magicSpell);
return om.orElseThrow(() -> new FailureToAmazeException("The box was empty"));
}
}
- 单元测试类,mock静态方法
@Test
@DisplayName("Should throw an exception upon failing to uncover mind-boggling mysteries")
void testUncoverMysteries() {
// 1.在try代码块中实例化一个MockedStatic,使用范围仅仅在try代码块内
try (MockedStatic<MysteryBox> mb = Mockito.mockStatic(MysteryBox.class)) {
// 2. mock静态方法的调用
mb.when(() -> { MysteryBox.amaze(any(String.class )) })
.thenReturn(Optional.empty());
// 3. 调用单元测试方法
assertThrows(FailureToAmazeException.class, () -> subjectUnderTest.unleashMystery("Abracadabra"));
}
// 静态方法的mock在这里是不可用的
}
3. 异常情况
在同个测试类,当多个测试方法都需要mock调用某个静态方法时,代码如下
@ExtendWith(MockitoExtension.class)
public class KonfigurationCopyServiceTest {
@InjectMocks
private EKonfigurationCopyServiceImpl konfigurationCopyServiceImpl;
@MockBean
private FileProcessRecordServiceImpl fileProcessRecordService;
@BeforeEach
public void setUp() {
// mock静态方法
MockedStatic<SpringUtil> mockSpringUtil = Mockito.mockStatic(SpringUtil.class);
mockSpringUtil.when(() -> SpringUtil.getActiveProfile()).thenReturn("dev");
}
@Test
void test1() {
// 省略@Test的单元测试方法
}
@Test
void test2() {
// 省略@Test的单元测试方法
}
}
此时,会抛出如下异常信息:
org.mockito.exceptions.base.MockitoException:
For xx.xxxx.util.SpringUtil, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
静态mock已经在当前线程中注册了,要创建新的mock,必须注销现有的静态mock注册
解决方式
- 导入
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
- 在测试类上添加注解
@TestInstance(PER_CLASS)
- 使用
@BeforeAll
代替@BeforeEach
// 添加@TestInstance(PER_CLASS)注解
@TestInstance(PER_CLASS)
@ExtendWith(MockitoExtension.class)
public class KonfigurationCopyServiceTest {
@InjectMocks
private EKonfigurationCopyServiceImpl konfigurationCopyServiceImpl;
@MockBean
private FileProcessRecordServiceImpl fileProcessRecordService;
// 使用@BeforeAll mock静态方法
@BeforeAll
public void setUp() {
// mock静态方法
MockedStatic<SpringUtil> mockSpringUtil = Mockito.mockStatic(SpringUtil.class);
mockSpringUtil.when(() -> SpringUtil.getActiveProfile()).thenReturn("dev");
}
@BeforeEach
public void init() {
// mock其他方法
}
@Test
void test1() {
// 省略@Test的单元测试方法
}
@Test
void test2() {
// 省略@Test的单元测试方法
}
}