Mockito单元测试对方法进行存根会抛出NullPointerException。

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

Mockito Unit Tests stubbing a method throws NullPointerException

问题

我正在为下面的类中的 run() 方法编写一些单元测试

public class TopicProcessor implements Runnable {

     private final KafkaConfig config;
     private final String inTopic;
     private final String outTopic;
     private final String inBroker;
     private final String outBroker;
     private KafkaConsumer<Long, byte[]> kafkaConsumer;
     private KafkaProducer<Long, byte[]> kafkaProducer;

     public void setKafkaConsumer(KafkaConsumer<Long, byte[]> kafkaConsumer) {
         this.kafkaConsumer = kafkaConsumer;
     }

     public void setKafkaProducer(KafkaProducer<Long, byte[]> kafkaProducer) {
         this.kafkaProducer = kafkaProducer;
     }

     public TopicProcessor(String topicKey, KafkaConfig config) {
         this.config = config;
         Map<String, Map<String, String>> mapping = this.config.getMapping(topicKey);
         this.inTopic = mapping.get("in").get("topic");
         this.outTopic = mapping.get("out").get("topic");
         this.inBroker = mapping.get("in").get("broker");
         this.outBroker = mapping.get("out").get("broker");
     }

     @Override
     public void run() {
         long now;
         getKafkaConsumer().subscribe(Collections.singletonList(this.inTopic));
         while (true) {
             ConsumerRecords<Long, byte[]> records = getKafkaConsumer().poll(Duration.ofMillis(100));
             meterInfo("consumer.received." + this.inTopic, records.count());
             for (ConsumerRecord<Long, byte[]> record : records) {
                 now = currentTimeMillis();
                 histogram("consumer.latency." + this.inTopic, now - record.timestamp());
                 getKafkaProducer().send(new ProducerRecord<>(this.outTopic, record.key(), record.value()));
                 meterInfo("publisher.sent." + this.outTopic);
             }
         }
     }
}

基本上,在 run() 方法中,我订阅了一个主题,使用 KafkaConsumer.poll() 方法轮询了所有记录,对于每条记录,我都使用了 KafkaProducer.send() 方法发送了记录。

我必须为以下情景编写单元测试:

  1. 测试 KafkaConsumer.poll() 方法是否调用了一次。
  2. 测试 KafkaProducer.send() 方法是否调用了一次。

以下是我的测试方法:

@Test
public void test(){
    // 模拟
    KafkaConsumer<Long, byte[]> consumerMock = mock(KafkaConsumer.class);
    KafkaProducer<Long, byte[]> producerMock = mock(KafkaProducer.class);

    // 测试数据
    Map<TopicPartition, List<ConsumerRecord<Long, byte[]>>> records = new LinkedHashMap<>();
    records.put(new TopicPartition("topic", 0), new ArrayList<>());
    ConsumerRecords<Long, byte[]> consumerRecords = new ConsumerRecords<>(records);

    ProducerRecord<Long, byte[]> producer_record = new ProducerRecord<>("topic", 1, 0L, 1L, new byte[]{'a'});

    // 创建对象以调用方法
    KafkaConfig kafkaConfig = new KafkaConfig(yamlConfig);
    TopicProcessor topicProcessor = new TopicProcessor("pacing_record", kafkaConfig);

    // 桩方法 - poll 和 send
    when(consumerMock.poll(Duration.ofMillis(anyInt()))).thenReturn(consumerRecords);  
    doReturn("sent").when(producerMock.send(producer_record, null));

    // 通过 setter 方法注入模拟对象
    topicProcessor.setKafkaConsumer(consumerMock);
    topicProcessor.setKafkaProducer(producerMock);

    // 调用上述类中的 run() 方法以验证是否调用了 kafka 方法
    topicProcessor.run();

    verify(consumerMock, times(1)).poll(Duration.ofMillis(anyInt()));
}

在上述测试方法中的以下行会抛出 NullPointerException

when(kafkaConsumerMock.poll(Duration.ofMillis(anyInt()))).thenReturn(consumerRecords);

有人知道如何正确地对方法进行桩方法,并验证是否被调用了吗?

英文:

I am writing some unit tests for the run() method in the below class

public class TopicProcessor implements Runnable {

     private final KafkaConfig config;
     private final String inTopic;
     private final String outTopic;
     private final String inBroker;
     private final String outBroker;
     private KafkaConsumer&lt;Long, byte[]&gt; kafkaConsumer;
     private KafkaProducer&lt;Long, byte[]&gt; kafkaProducer;


     public void setKafkaConsumer(KafkaConsumer&lt;Long, byte[]&gt; kafkaConsumer) {
         this.kafkaConsumer = kafkaConsumer;
     }

     public void setKafkaProducer(KafkaProducer&lt;Long, byte[]&gt; kafkaProducer) {
         this.kafkaProducer = kafkaProducer;
     }

     public TopicProcessor(String topicKey, KafkaConfig config) {
         this.config = config;
         Map&lt;String, Map&lt;String, String&gt;&gt; mapping = this.config.getMapping(topicKey);
         this.inTopic = mapping.get(&quot;in&quot;).get(&quot;topic&quot;);
         this.outTopic = mapping.get(&quot;out&quot;).get(&quot;topic&quot;);
         this.inBroker = mapping.get(&quot;in&quot;).get(&quot;broker&quot;);
         this.outBroker = mapping.get(&quot;out&quot;).get(&quot;broker&quot;);
     }


     @Override
     public void run() {
         long now;
         getKafkaConsumer().subscribe(Collections.singletonList(this.inTopic));
         while (true) {
             ConsumerRecords&lt;Long, byte[]&gt; records = getKafkaConsumer().poll(Duration.ofMillis(100));
             meterInfo(&quot;consumer.received.&quot; + this.inTopic, records.count());
             for (ConsumerRecord&lt;Long, byte[]&gt; record : records) {
                 now = currentTimeMillis();
                 histogram(&quot;consumer.latency.&quot; + this.inTopic, now - record.timestamp());
                 getKafkaProducer().send(new ProducerRecord&lt;&gt;(this.outTopic, record.key(), record.value()));
                 meterInfo(&quot;publisher.sent.&quot; + this.outTopic);
             }
         }
     }

Basically, In the run() method, I am subscribed to a topic, polled all records using KafkaConsumer.poll() method and for each record, I am sending the record using KafkaProducer.send() method.

I have to write unit tests for below scenario : -

  1. Test that KafkaConsumer.poll() method called one time
  2. Test that KafkaProducer.send() method called one time

Below is my Test method: -

@Test
public void test(){
    //Mocks
    KafkaConsumer&lt;Long, byte[]&gt; consumerMock = mock(KafkaConsumer.class);
    KafkaProducer&lt;Long, byte[]&gt; producerMock = mock(KafkaProducer.class);

    //test data
    Map&lt;TopicPartition, List&lt;ConsumerRecord&lt;Long, byte[]&gt;&gt;&gt; records = new LinkedHashMap&lt;&gt;();
records.put(new TopicPartition(&quot;topic&quot;, 0), new ArrayList&lt;&gt;());
    ConsumerRecords&lt;Long, byte[]&gt; consumerRecords = new ConsumerRecords&lt;&gt;(records);

    ProducerRecord&lt;Long, byte[]&gt; producer_record = new ProducerRecord&lt;Long, byte[]&gt;(&quot;topic&quot;, 1, 0L, 1L, new byte[]{&#39;a&#39;});

    //object creation to call the method
    KafkaConfig kafkaConfig = new KafkaConfig(yamlConfig);
    TopicProcessor topicProcessor = new TopicProcessor(&quot;pacing_record&quot;, kafkaConfig);

    //stubbing Kafka methods - poll and send
    when(consumerMock.poll(Duration.ofMillis(anyInt()))).thenReturn(consumerRecords);  
    doReturn(&quot;sent&quot;).when(producerMock.send(producer_record, null));

    //Injecting mocks thorugh setter method
    topicProcessor.setKafkaConsumer(consumerMock);
    topicProcessor.setKafkaProducer(producerMock);

    //calling a class method run() from above class to verify that kafka methods are called
    topicProcessor.run();

    verify(consumerMock, times(1)).poll(Duration.ofMillis(anyInt()));

}

Below line in the above test method throws NullPointerException

    when(kafkaConsumerMock.poll(Duration.ofMillis(anyInt()))).thenReturn(consumerRecords);

Anyone know how to correctly stub the method and verify it is called or not?

答案1

得分: 0

when(kafkaConsumerMock.poll(Duration.ofMillis(anyInt())))

这是对Mockito的错误使用。`any*` 方法只应作为模拟方法的直接参数使用。

我认为你在这里想表达的是:“对于任何持续时间,我不关心它有多长”。如果是这样,你可以表示为:

when(kafkaConsumerMock.poll(any(Duration.class)))

或者

when(kafkaConsumerMock.poll(any()))

如果没有歧义性重载。

类似地,用于验证:

verify(kafkaConsumerMock, times(1)).poll(any(Duration.class))
英文:
when(kafkaConsumerMock.poll(Duration.ofMillis(anyInt())))

This is an incorrect usage of Mockito. The any* methods should only be used as the direct parameters to the mocked method.

I think what you're trying to say here is "for any duration, I don't care how long it is". If so, you can express that as:

when(kafkaConsumerMock.poll(any(Duration.class))

or

when(kafkaConsumerMock.poll(any())

if there is no ambiguous overload.

Similarly, to verify:

verify(kafkaConsumerMock, times(1)).poll(any(Duration.class))

huangapple
  • 本文由 发表于 2020年5月31日 06:30:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/62109414.html
匿名

发表评论

匿名网友

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

确定