Spring Boot单元测试中,不启动容器用@Mock+@InjectMocks,需上下文时用@MockBean+@SpringBootTest;工厂非Spring Bean则@Mock并when().thenReturn()打桩,是Spring Bean则用@MockBean替换;须verify验证调用、避免null返回,并注意静态方法、ThreadLocal等特殊场景处理。

Spring Boot 单元测试中,模拟工厂返回的对象并完成容器注入,关键在于区分两种场景:是否需要 Spring 上下文。不启动容器时用 @Mock + @InjectMocks;需要上下文(比如依赖 AOP、事务、自动装配逻辑)时则必须用 @MockBean 配合 @SpringBootTest。
工厂类本身需要被模拟
当业务代码通过工厂获取对象(如 UserFactory.createUser()),而该工厂不是 Spring 管理的 Bean 时:
- 直接用
@Mock注解工厂类实例,并在@BeforeEach中调用MockitoAnnotations.openMocks(this) - 用
when(factory.createUser()).thenReturn(mockUser)打桩返回值 - 确保待测类通过构造器或 setter 注入该工厂,否则
@InjectMocks无法自动装配
工厂是 Spring Bean,需替换为 Mock 实例
若工厂类本身由 Spring 管理(如 @Component 或 @Service 标记),且你希望它在整个应用上下文中被统一替换:
- 使用
@MockBean注解工厂类字段,Spring Boot Test 会自动将其注册进上下文并覆盖原 Bean - 无需手动打桩静态方法;但若工厂内部调用了静态工具类,仍需用
Mockito.mockStatic()单独处理 - 注意:同一个测试类中不能同时对同一类型声明
@Mock和@MockBean,否则可能引发冲突
注入容器后验证对象是否生效
无论用哪种方式,最终要确认模拟对象真正参与了运行逻辑:
- 调用待测方法后,用
verify(mockFactory, times(1)).createUser()确认工厂方法被调用 - 若工厂返回的是复杂对象(如带 Builder 的 DTO),建议用
ArgumentCaptor捕获传入参数做细粒度断言 - 避免在打桩时返回
null或未初始化对象,尤其当后续逻辑有非空校验时,容易导致 NPE 而非测试失败
常见陷阱与绕过方案
有些工厂返回单例、缓存实例或依赖静态状态,常规 mock 可能失效:
- 静态工厂方法:必须用
mockStatic(YourFactory.class),并在测试结束后调用close() - 内部持有线程局部变量(ThreadLocal):需在
@BeforeEach中清理,或用reset()重置 mock 状态 - 工厂返回 Spring Bean(如
ApplicationContext.getBean()):应优先改造成依赖注入,而非在运行时动态获取,否则难以 mock

















