SpringBoot Kafka全链路测试中Mock嵌套依赖RestTemplate失效问题
问题根因
你的Mock不生效核心是注解使用逻辑完全错了:
@SpringBootTest会启动完整的Spring IoC容器,你业务里标注了@Service的KafkaConsumer、MyFacade、MyClient,以及Spring自动配置的真实RestTemplate都会被注册为容器内的Bean,Kafka消息消费的整条链路走的全是容器里的真实实例。- 你写的
@Mock、@InjectMocks是Mockito原生注解,修饰的对象是Mockito反射创建的独立实例,根本不会被注册到Spring容器里,和实际运行的调用链路完全没关系,你对这些对象打的桩自然不会生效。 - 额外两个小问题:一是代码里
Mokito.when拼写错误,正确类名是Mockito;二是Kafka消费是异步流程,你发完消息直接结束测试方法,大概率消费逻辑还没执行到测试就退出了。
修复方案
直接用Spring Boot测试模块提供的@MockBean注解替换原生@Mock,这个注解会自动把Mock生成的对象替换掉Spring容器内同类型的真实Bean,整条依赖链里注入的都会是Mock实例,不需要手动用@InjectMocks一层层注入。
正确测试代码示例:
@ActiveProfiles("test") @RunWith(SpringRunner.class) @SpringBootTest @EmbeddedKafka(partitions = 1, topics = {"替换成你实际的监听topic"}) public class KafkaConsumeTest { // 替换容器中真实的RestTemplate为Mock实例 @MockBean private RestTemplate restTemplate; @Autowired private KafkaProducer producer; @Autowired private KafkaListenerEndpointRegistry registry; @Test public void testFullConsumeLogic() throws Exception { // 给RestTemplate打桩,匹配参数时如果不想写死可以用Mockito参数匹配器 Mockito.when(restTemplate.exchange( Mockito.anyString(), Mockito.any(HttpMethod.class), Mockito.any(HttpEntity.class), Mockito.eq(Void.class) )).thenReturn(new ResponseEntity<>(HttpStatus.OK)); // 发送测试消息,同步等待发送完成 producer.send("替换成你实际的监听topic", "My Kafka Message") .get(3, TimeUnit.SECONDS); // 等待Kafka监听器分区分配完成 registry.getListenerContainers().forEach(container -> ContainerTestUtils.waitForAssignment(container, 1) ); // 等待异步消费逻辑执行完成,校验Mock调用符合预期 Awaitility.await().atMost(5, TimeUnit.SECONDS) .untilAsserted(() -> Mockito.verify(restTemplate, Mockito.times(1)) .exchange( Mockito.anyString(), Mockito.any(HttpMethod.class), Mockito.any(HttpEntity.class), Mockito.eq(Void.class) )); } }
注意事项
- 删掉测试类里所有
@InjectMocks修饰的对象,业务类直接使用Spring容器内的真实实例即可,@MockBean已经替换了链路底层的RestTemplate,不会发起真实HTTP请求。 - 不要发完消息立刻结束测试,必须加等待逻辑:可以用示例里的
Awaitility轮询校验Mock调用,也可以自定义CountDownLatch在业务逻辑执行完成后计数,避免异步流程没跑完测试就退出。 - 你的依赖里同时引入了JUnit4和JUnit5的组件,当前用
@RunWith(SpringRunner.class)是JUnit4的运行逻辑,建议移除junit-jupiter-engine依赖避免注解冲突,如果要升级JUnit5替换成@ExtendWith(SpringExtension.class)即可,不影响当前Mock逻辑。
内容的提问来源于stack exchange,提问作者Ging3r
相关产品推荐
相关产品推荐

