关键在于设计可测试代码:依赖必须显式注入而非内部new;用@Mock和@InjectMocks组合注入,配合@ExtendWith启用;行为定义需精准匹配调用路径;复杂嵌套需分层mock或改用@Spy/Supplier。

关键不在“怎么写”,而在“怎么设计”——Mockito 本身不解决模拟问题,它只放大你代码里已有的可测试性缺陷。真正让 Mockito 生效的,是把依赖变成可替换的入口。
依赖必须显式传入,不能在类内部 new
Mockito 只能控制你给出去的对象,无法拦截类自己 new 出来的实例。如果被测类像这样写:
-
错误写法:在方法里直接
new HttpClient()或调用new ServiceImpl() - 正确做法:把 HttpClient 或 ServiceImpl 声明为字段,并通过构造函数或 setter 注入
例如,把 private final ApiClient client = new ApiClient(); 改成:private final ApiClient client;public MyService(ApiClient client) { this.client = client; }
用 @Mock + @InjectMocks 组合注入(推荐初学者)
这是最简洁的入门方式,适合 Spring 风格或轻量级业务类:
-
@Mock创建模拟对象(如@Mock UserRepository userRepository) -
@InjectMocks自动把所有@Mock实例按类型/名称注入到被测对象中(如@InjectMocks UserService userService) - 需配合
@ExtendWith(MockitoExtension.class)启用注解支持(JUnit 5)
注意:@InjectMocks 会尝试构造器注入 > setter 注入 > 字段注入,优先使用带参构造器,避免字段注入带来的 null 风险。
立即学习“Java免费学习笔记(深入)”;
行为定义要覆盖真实调用路径
模拟不是“声明一下就完事”,必须精准匹配运行时实际触发的方法调用:
- 用
when(mock.method(arg)).thenReturn(result)预设返回值 - 对 void 方法,用
doThrow(...).when(mock).method()或doAnswer(...).when(mock).method() - 验证是否调用:用
verify(mock, times(1)).method(arg),别漏掉参数匹配(如eq("id")、anyString())
常见陷阱:mock 对象的方法没被 when 定义,又没被 verify,结果执行了默认返回(null/0/false),导致 NPE 或逻辑跳过——这不是 Mockito 的错,是你没声明契约。
复杂嵌套返回值需要分层 mock
当一个方法返回的对象还要继续调用其方法(比如 response.getBody().getData()),就得逐层模拟:
- 先 mock
Response对象 - 再 mock
response.getBody()返回的Body对象 - 最后 mock
body.getData()的返回值
或者更稳妥地,用 @Spy 包裹真实对象,只 stub 关键方法;或重构为 Supplier 接口,把对象创建逻辑外移,便于测试时替换。


















