@MockBean用于在Spring Boot测试中动态替换容器内真实Bean,通过注入Mockito Mock实现外部依赖隔离,确保测试快速、稳定、可重复,作用域限于当前测试类或方法。

核心思路是:用 @MockBean 或 @Mock 替换真实依赖,让被测业务逻辑在无外部干扰的环境下运行,只验证它“自己该做什么”。不启动数据库、不调用远程服务、不写入文件,测试就快、稳、准。
明确测试目标:只测 Service 方法本身
单元测试不是跑通整个流程,而是确认一个方法在给定输入下是否返回预期结果、是否触发了正确的行为(比如是否调用了某个 DAO)、是否按逻辑处理了异常。例如:
- 用户注册方法是否生成了正确 ID 并保存到 UserRepository?
- 订单创建时库存不足,是否抛出
InsufficientStockException? - 支付回调成功后,是否调用了通知服务发送短信?
选对注解:@MockBean vs @Mock
关键看是否需要 Spring 容器参与:
-
@MockBean:用于
@SpringBootTest或切片测试(如@WebMvcTest)。它会把 Mock 对象注入 Spring 上下文,替换掉同类型的真 Bean。适合测试中仍需 Spring 管理的类(如带@Transactional的 Service)。 -
@Mock + @InjectMocks:纯 Mockito 单元测试,不加载 Spring 容器。速度快,适合逻辑复杂但依赖简单的 Service。Mockito 自动把
@Mock对象注入到@InjectMocks标记的被测对象中。
模拟依赖行为:用 when().thenReturn() 和 doThrow()
不能只“创建 Mock”,必须定义它“怎么响应”:
立即学习“Java免费学习笔记(深入)”;
- 正常路径:
when(userRepository.save(any(User.class))).thenReturn(savedUser); - 空值路径:
when(orderRepository.findById(99L)).thenReturn(Optional.empty()); - 异常路径:
doThrow(new PaymentTimeoutException()).when(paymentService).process(any(PaymentRequest.class));
注意:对 void 方法或 setter 类操作,必须用 doThrow() 或 doAnswer(),不能用 when()。
验证执行过程:verify() 比返回值更重要
除了检查方法返回结果,还要确认它是否做了该做的事:
- 是否调用了依赖的某方法:
verify(userRepository).save(any(User.class)); - 是否只调用了一次:
verify(emailService, times(1)).sendWelcomeEmail(any(User.class)); - 是否没调用不该调用的方法:
verifyNoInteractions(analyticsService);
这能防止“结果碰巧对,但逻辑走错了”的隐蔽缺陷。


















