Mockito核心API详解
1. 创建Mock对象
Mockito提供两种方式创建模拟对象:
1.1 手动创建(传统方式)
// 创建接口/类的Mock对象
UserDao userDao = Mockito.mock(UserDao.class);
1.2 注解驱动(推荐方式)
结合JUnit 5的扩展机制,自动管理Mock生命周期:
@ExtendWith(MockitoExtension.class) // 启用Mockito支持
class UserServiceTest {@Mock // 自动创建Mock对象private UserDao mockUserDao;@InjectMocks // 自动注入@Mock对象到被测类private UserService userService;
}
选择策略:
- 简单测试 → 手动创建
- 多依赖测试 → 注解驱动(避免重复代码)
2. 方法桩(Stubbing)
控制Mock对象方法的返回值或异常抛出。
2.1 基础配置
// 返回固定值
when(mockUserDao.findById(1)).thenReturn(new User("Alice"));// 抛出异常
when(mockUserDao.save(any())).thenThrow(new DatabaseException());// 连续配置(依次返回)
when(mockList.get(0)).thenReturn("A", "B", "C"); // 第一次"A",第二次"B"...
2.2 动态响应
// 根据输入参数动态计算返回值
when(mockCalculator.add(anyInt(), anyInt())).thenAnswer(invocation -> {int a = invocation.getArgument(0);int b = invocation.getArgument(1);return a + b;
});// 调用真实方法(部分保留逻辑)
when(mockUserDao.findById(1)).thenCallRealMethod();
2.3 Void方法处理
// 默认不做任何事情
doNothing().when(mockLogger).writeLog(anyString());// 抛出异常
doThrow(new IOException()).when(mockFileService).deleteFile(any());
3. 验证交互行为
验证Mock对象的方法是否按预期被调用。
3.1 基础验证
verify(mockUserDao).findById(1); // 验证方法被调用一次
3.2 调用次数验证
verify(mockUserDao, times(2)).update(any()); // 精确次数
verify(mockUserDao, atLeastOnce()).delete(5); // 至少一次
verify(mockUserDao, never()).findAll(); // 从未调用
3.3 顺序验证
InOrder inOrder = inOrder(mockA, mockB);
inOrder.verify(mockA).prepare();
inOrder.verify(mockB).execute();
3.4 超时验证(异步场景)
// 200ms内至少调用一次
verify(mockAsyncService, timeout(200)).callback();
4. 参数匹配器(Argument Matchers)
灵活匹配方法参数,增强测试的适应性和可读性。
4.1 内置匹配器
// 任意字符串参数
when(mockUserDao.findByUsername(anyString())).thenReturn(...);// 混合精确与模糊匹配
when(service.process(eq("order"), anyInt())).thenReturn(true);
4.2 自定义匹配器
// 定义复杂参数条件
verify(mockValidator).validate(argThat(user -> user.getAge() > 18 && user.isVerified()
));
注意事项:
- 若方法中多个参数使用匹配器,所有参数必须都用匹配器
- 避免过度使用
any()
→ 可能导致测试条件过于宽松
5. 高级功能API
5.1 Spy对象(部分真实对象)
List<String> realList = new ArrayList<>();
List<String> spyList = spy(realList); // 保留真实方法// 覆盖特定方法行为
doReturn(false).when(spyList).isEmpty();
5.2 参数捕获(ArgumentCaptor)
@Captor // 自动初始化
private ArgumentCaptor<User> userCaptor;@Test
void testSaveUser() {userService.register("Bob");verify(mockUserDao).save(userCaptor.capture());User capturedUser = userCaptor.getValue();assertEquals("Bob", capturedUser.getName());
}
5.3 重置Mock状态
reset(mockUserDao); // 慎用!通常表示测试设计有问题
核心API对照表
API | 典型应用场景 |
---|---|
mock() / @Mock | 创建完全模拟的假对象 |
when().thenReturn() | 配置方法返回固定值 |
verify() | 验证方法调用情况 |
any() / eq() | 参数灵活匹配 |
@Spy | 需要保留部分真实逻辑的对象 |
ArgumentCaptor | 深入分析传入方法的参数内容 |
最佳实践建议
- 优先使用注解驱动:
@Mock
+@InjectMocks
提升代码可读性和维护性。 - 精确验证参数:
避免过度使用any()
,尽可能用eq()
或具体值匹配关键参数。 - 及时清理过时桩:
使用Mockito.clearInvocations(mock)
而非reset()
。 - 保持测试原子性:
每个测试方法只验证一个明确的业务场景。
通过掌握这些核心API,开发者可以高效构建可靠、易维护的单元测试体系。接下来可进入参数匹配器实战学习更精细的控制技巧。