如何用Mockito正确测试带回调的Kafka Producer send方法?
解决Mockito测试中回调分支未执行的问题
你的问题其实有两个核心点需要解决:回调函数没有被主动触发,以及静态Logger无法被Mock注入,我一步步给你讲清楚怎么调整:
1. 为什么回调没进入if分支?
Mockito默认情况下,当你mock像producer.send()这类带回调参数的方法时,它只会按你设定的返回值返回(比如你这里的thenReturn(null)),但不会主动执行你传入的Callback接口的onCompletion方法。所以你的if/else分支根本没机会运行,自然就verify不到日志输出了。
解决这个问题的核心是:拦截send方法的调用,手动取出回调对象并触发它。
2. 为什么Logger的verify会失败?
你原类中的LOGGER是static final类型的静态字段,@InjectMocks只能注入实例字段,管不到静态属性。所以你@Mock的logger根本没被用到,原类还是用的真实Logger实例,这也是verify失败的隐藏原因。
3. 修改后的测试代码
下面是调整后的完整测试代码,我加了详细注释:
@RunWith(MockitoJUnitRunner.class) public class SomeClassTest { @InjectMocks private SomeClass someclass; @Mock private Producer<String, SpecificRecord> producer; @Mock private SpecificRecord message; @Mock private Logger logger; @Test public void sendMessageTest() { // 第一步:Mock静态的Logger.Factory,让它返回我们的mock logger try (MockedStatic<Logger.Factory> mockedLoggerFactory = Mockito.mockStatic(Logger.Factory.class)) { mockedLoggerFactory.when(() -> Logger.Factory.getLogger(SomeClass.class)) .thenReturn(logger); // 第二步:拦截producer.send的调用,手动触发回调 doAnswer(invocation -> { // 取出方法调用时传入的第二个参数——也就是Callback对象 Callback callback = invocation.getArgument(1); // 调用回调的onCompletion方法,传入null作为exception,触发OK分支 callback.onCompletion(null, null); // send方法返回Future,这里返回null即可 return null; }).when(producer).send(any(ProducerRecord.class), any(Callback.class)); // 预设flush方法什么都不做 doNothing().when(producer).flush(); // 执行测试方法 someclass.sendMessage("topic", message, new HashMap<String, String>()); // 验证日志是否被正确调用 verify(logger).info("OK"); } } }
4. 扩展:测试异常分支
如果想测试exception != null的NOK分支,只需要修改回调触发的代码:
// 在doAnswer里传入一个非null的Exception callback.onCompletion(null, new RuntimeException("测试异常")); // 然后验证NOK日志 verify(logger).info("NOK");
注意事项
- 这个方案要求你使用Mockito 3.4.0及以上版本,因为
mockStatic是从这个版本开始引入的官方静态Mock功能。如果你用的是老版本,可以考虑升级Mockito,或者用PowerMock来实现静态Mock。 - 如果需要更精确的参数匹配,比如验证ProducerRecord的topic、key等是否正确,可以把
any(ProducerRecord.class)换成argThat来做自定义匹配。
内容的提问来源于stack exchange,提问作者oitathi
相关产品推荐
相关产品推荐

