Spring单元测试Mockito Mock @Autowired字段返回null问题
Spring Boot单元测试Mock注入失效、Stub返回null修复方案
直接导致问题的根因
- 测试类注解冲突:
@RunWith(SpringRunner.class)是JUnit4专属的Spring测试运行器,@ExtendWith(MockitoExtension.class)是JUnit5专属的Mockito扩展,二者同时声明会导致测试上下文初始化冲突,Mock的Stub逻辑被上下文覆盖失效 - 参数匹配逻辑错误:初始化方法中新建的
InputObj实例是测试侧的独立对象,业务逻辑执行时内部生成的InputObj实例和该实例不是同一个引用,Mockito默认按对象equals做严格参数匹配,匹配失败时Mock方法默认返回null - 注解选型错误:Spring上下文托管的Bean做Mock替换时,用
@Mock+@InjectMocks、手动Mockito.mock()生成的Mock对象不会注册到Spring容器,业务类注入的还是容器中真实的Comm实例,会直接执行真实方法逻辑 @AsyncAOP代理干扰:标注@Async的类会被Spring生成代理子类,代理对象可能绕过注入的Mock引用,调用真实Bean的方法- 代码语法问题:原测试类声明
public class testProcessorClass()带多余括号,不符合Java语法,类名也不符合大驼峰规范,会直接导致编译/运行异常
可直接落地的修复步骤(无需修改业务类构造函数)
1. 清理冲突的测试类注解
保留和JUnit4匹配的Spring测试注解,删除不兼容的JUnit5扩展,同时禁用测试环境的异步自动配置,避免AOP代理干扰:
@RunWith(SpringRunner.class) @SpringBootTest(properties = "spring.task.execution.async.enabled=false") @ContextConfiguration(classes = {...}) // 原有配置类保留 public class TestProcessorClass {
2. 修正Mock注入与Stub逻辑
使用@MockBean将Comm的Mock对象注册到Spring容器,替换原有真实Bean;Stub时使用宽松参数匹配器,避免对象引用不一致导致的匹配失败:
@Autowired Cache cache; @MockBean Comm comm; @Autowired Processor processor; @Before public void init() { ReturnData presetReturn = new ReturnData(); // 任意InputObj实例都匹配,第二个参数精确匹配硬编码的"id" Mockito.doReturn(presetReturn) .when(comm) .checkOut(Mockito.any(InputObj.class), Mockito.eq("id")); } @Test public void testProcessorMethod() { // 注意核对方法名:原Processor类贴出的方法名是processResponse,不要写错成processRequest Request reqData = new Request(versionId, dataString); Response response = processor.processResponse(reqData); // 后续断言逻辑 }
如果需要严格校验入参,不要用
any(InputObj.class),可以改用Mockito.argThat()自定义匹配规则,校验InputObj的字段值符合预期即可,不需要对象引用完全相等。
额外注意事项
注意:@MockBean是Spring Boot Test提供的专属注解,作用是将生成的Mock对象注册到Spring应用上下文,自动替换容器中同类型的真实Bean,是启动Spring上下文的集成测试场景下替换依赖的正确方式,不要和纯Mockito场景的@Mock注解混用。
- 不要在Spring集成测试场景下混用
@InjectMocks:该注解是Mockito独立依赖注入的标记,不会将Mock注入到Spring容器托管的Bean中,仅适用于不启动Spring上下文的纯单元测试 - 不要手动调用
Mockito.mock()生成Spring依赖的Mock:手动生成的对象不在Spring容器中,无法替换业务类自动注入的真实实例 - 如果需要保留
@Async的异步执行逻辑,不要禁用异步配置,改为注入AsyncTaskExecutor手动等待异步任务执行完成后再做断言即可,Stub逻辑写法保持不变
内容的提问来源于stack exchange,提问作者src2012
相关产品推荐
相关产品推荐

