Mockito 是什么
Mockito 是 Java 单元测试中最常用的替身框架:用 @Mock 生成模拟对象、when(...).thenReturn(...) 定义桩行为、verify(...) 校验调用是否按预期发生。它让被测逻辑与外部依赖(下游服务、数据库、时钟)隔离,异常与超时等真实环境难以复现的分支也能稳定构造。配合 MockitoExtension 自动初始化注解,样板代码降到最低。
基本信息
| 核心三件套 | 打桩 when/thenReturn、验证 verify、替身 @Mock/@Spy |
|---|---|
| 注入方式 | @InjectMocks 把替身注入被测对象 |
| 扩展集成 | @ExtendWith(MockitoExtension.class) 自动初始化注解 |
| 严格模式 | 未使用的桩会报 UnnecessaryStubbingException |
| 参数匹配器 | any()、eq() 等 ArgumentMatchers 匹配调用参数 |
| 参数捕获 | ArgumentCaptor 捕获调用时的真实参数做断言 |
示例
示例
@ExtendWith(MockitoExtension.class)
class PaymentTest {
@Mock Gateway gateway; // 替身:不调用真实下游
@InjectMocks PaymentService service;
@Test
void pays() {
when(gateway.charge(100)).thenReturn(true); // 打桩:定义返回
assertTrue(service.pay(100));
verify(gateway).charge(100); // 验证:调用发生且参数正确
}
@Test
void timeout_isWrapped() {
when(gateway.charge(anyInt())).thenThrow(new TimeoutException()); // 异常分支
assertThrows(PayFailedException.class, () -> service.pay(100));
}
}典型使用场景
- 隔离下游依赖:支付网关、短信通道等外部服务不参与单元测试。
- 异常分支构造:用 thenThrow 覆盖超时、拒绝、限流等难复现路径。
- 交互验证:确认服务按协议调用下游且次数、参数正确。
- 参数断言:用 ArgumentCaptor 捕获请求体,验证序列化与字段组装。
- 遗留代码加测试:先给难拆的依赖打桩,建立安全网后再重构。
- 契约收紧:把上下游调用协议固化进 verify,协议变化时测试先报警。
常用能力对照
| 能力 | 写法 | 说明 |
|---|---|---|
| 定义返回 | when(x).thenReturn(v) | 连续调用可用 thenReturn(v1, v2) |
| 抛异常 | thenThrow(...) | 覆盖下游出错分支 |
| void 方法 | doThrow/doNothing | void 无法用 when(...) 包住 |
| 调用验证 | verify(x).m() | 配合 times/never/atLeast 控制次数 |
| 参数捕获 | ArgumentCaptor | 断言调用时实际传入的对象 |
| 部分替身 | @Spy | 默认调真实方法,谨慎打桩 |
替身只用于边界:外部服务、时间、随机数这类不可控因素是打桩对象;被测对象内部的协作类尽量真实,打桩打太深测试会与实现细节耦合。
严格模式下未使用的桩会报错:这不是麻烦而是卫生检查,能逼出过期桩与写错的匹配参数,不要图省事整体关闭严格模式。
未打桩的方法调用返回默认值(null、0、false):默认值可能把断言悄悄带过,关键路径应显式定义桩行为。