如何使用Mockito测试带有回调的Kafka生产者的send方法?

huangapple go评论79阅读模式
英文:

How to test the send method from a Kafka Producer with callback using mockito?

问题

我正在尝试测试一个方法为此我正在使用mockito然而我的模拟在进入if语句的条件中时没有生效直接跳到了flush语句那一行

我想要测试以下情况

    public class SomeClass{
         @Autowired
         private Producer<String, SpecificRecord> producer;

         private static final Logger LOGGER = Logger.Factory.getLogger(SomeClass.class);

         public void sendMessage(String topic, SpecificRecord message, Map<String,String> headers){
             ProducerRecord<String, SpecificRecord> avroMessage = new ProducerRecord<>(topic, null, null, "key", message, headers);
             producer.send(avroMessage, (metadata, exception) -> {
                 if(exception == null ) {
                     LOGGER.info("OK");
                 }else{ 
                     LOGGER.info("NOK");
                 }
             });
             producer.flush();
        }

而我正在做的是

    @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(){
            when(producer.send(any(ProducerRecord.class),any(Callback.class))).thenReturn(null);
            doNothing().when(producer).flush();
            
            someclass.sendMessage("topic", message, new HashMap<String,String>());
            verify(logger).info("OK");
        }
    }
        

我应该如何正确模拟这种情况
英文:

I am trying to test a method and for that I am using mockito. However, my mock is not getting inside into the if's condition and goes directly to the flush's line.

I would like to test the follow situation:

public class SomeClass{
@Autowired
private Producer&lt;String, SpecificRecord&gt; producer;
private static final Logger LOGGER = Logger.Factory.getLogger(SomeClass.class);
public void sendMessage(String topic, SpecificRecord message, Map&lt;String,String&gt; headers){
ProducerRecord&lt;String, SpecificRecord&gt; avroMessage = new ProducerRecord&lt;&gt;(topic, null, null, &quot;key&quot;,message, headers);
producer.send(avroMessage, (metadata, exception) -&gt; {
if(exception == null ) {
LOGGER.info(&quot;OK&quot;);
}else{ 
LOGGER.info(&quot;NOK&quot;);
}
});
producer.flush();
}

And what I'm doing is it:

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest{
@InjectMocks
private SomeClass someclass;
@Mock
private Producer&lt;String,SpecificRecord&gt; producer;
@Mock
private SpecificRecord message;
@Mock
private Logger logger;
@Test
public void sendMessageTest(){
when(producer.send(any(ProducerRecord.class),any(Callback.class))).thenReturn(null);
doNothing().when(producer).flush();
someclass.sendMessage(&quot;topic&quot;, message, new HashMap&lt;String,String&gt;());
verify(logger).info(&quot;OK&quot;);
}
}

What can I do to mock this situation correctly?

答案1

得分: 2

使用以下 lambda 表达式,您正在实现 Callback 接口(接口 Callback)的 onCompletion 方法:

(metadata, exception) -&gt; {
         if(exception == null ) {
             LOGGER.info("OK");
         }else{ 
             LOGGER.info("NOK");
         }
     }

由于您正在模拟 KafkaProducer 的 send 方法调用,该回调不会被调用。
因此,为了能够进入回调调用,您需要捕获 Callback 参数,并按如下方式调用 onCompletion 方法:

ArgumentCaptor<Callback> callBackCaptor = ArgumentCaptor.forClass(Callback.class);
Mockito.verify(producer).send(any(ProducerRecord.class), callBackCaptor.capture());
Callback kafkaCallback = callBackCaptor.getValue();
kafkaCallback.onCompletion(new RecordMetadata(null, 0, 0, 0, 0, 0, 0), null);
英文:

By using the lambda expression below, you are implementing the onCompletion method of the Callback interface (Interface Callback)

(metadata, exception) -&gt; {
if(exception == null ) {
LOGGER.info(&quot;OK&quot;);
}else{ 
LOGGER.info(&quot;NOK&quot;);
}
}

And since you are mocking the KafkaProducer send method call, that callback won't be called.
So, to be able to get inside the callback call, you have to capture the Callback argument and call the onCompletion method as below:

    ArgumentCaptor&lt;Callback&gt; callBackCaptor = ArgumentCaptor.forClass(Callback.class);
Mockito.verify(producer).send(any(ProducerRecord.class), callBackCaptor.capture());
Callback kafkaCallback = callBackCaptor.getValue();
kafkaCallback.onCompletion(new RecordMetadata(null, 0, 0, 0, 0, 0, 0), null);

huangapple
  • 本文由 发表于 2020年9月9日 23:07:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/63814528.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定