单元测试 ListenableFuture kafkaTemplate.send 总是 returns null

unit testing ListenableFuture kafkaTemplate.send always returns null

我正在尝试对来自 kafkaTemplate.send() 的回调进行单元测试,但它没有按预期工作。这是我正在尝试测试的代码片段。

    @Override
    public void sendMessage(String topicName, String message) {

        ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(topicName, message);
        future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {

            @Override
            public void onSuccess(SendResult<String, String> result) {
                System.out.print("Success")
            }
            @Override
            public void onFailure(Throwable ex) {
                System.out.print("Failed")
            }
        });
    }

这是单元测试代码


    private KafkaTemplate<String, String> kafkaTemplate;
    private KafkaService kafkaService;
    private SendResult<String, String> sendResult;
    private ListenableFuture<SendResult<String, String>> future;
    private RecordMetadata recordMetadata
    private String topicName
    private String message



    def setup() {
        kafkaTemplate = Mock(KafkaTemplate.class)
        kafkaService = new KafkaService(kafkaTemplate);
        topicName = "test.topic"
        message = "test message"
        sendResult = Mock(SendResult.class);
        future = Mock(ListenableFuture.class);
        recordMetadata = new RecordMetadata(new TopicPartition(topicName, 1), 1L, 0L, 0L, 0L, 0, 0);
    }

    def "Test success send message method"() {
        given:
        sendResult.getRecordMetadata() >> recordMetadata
        kafkaTemplate.send(_ as String, _ as String) >> future

        when:
        kafkaService.sendMessage(topicName, message)

        then:
        // catch success or failed here.

        1 * kafkaTemplate.send(_,_) >> {arguments ->
            final String topicNameParam = arguments.get(0)
            final String messageParam = arguments.get(1)

            assert topicNameParam == topicName
            assert messageParam == message
        }
    }

基于调试器 future 在这种情况下为空

ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(topicName, message); // future null
 future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() { // future null

我已经在这里阅读了很多答案,但并没有解决问题,或者他们没有很好地解释我会明白问题出在哪里。像这个

提前感谢您的帮助!

因为你在嘲笑 KafkaTemplate;您需要将发送方法模拟为 return 未来。

我对 Spock 不熟悉。

对于 Mockito,这将是

SettableListenerFuture<SendResult<?, ?>> future = new SettableListenerFuture<>();
given(template.send(anyString(), anyString())).willReturn(future);

您在尝试 combine mocking and stubbing 时犯了一个典型的 Spock 初学者错误:首先在 given: 块中声明一个存根结果,然后声明一个检查的模拟交互(without 存根结果)在 then: 块中。但是 mocking 和 stubbing 总是必须在同一个交互中发生 正如我链接到的手册章节中所描述的那样。该手册还解释说 then: 块中的交互在您的情况下获胜,即因为您没有在那里指定存根结果,结果将默认为 null.

此外,您使论证验证变得比必要的困难得多。只需使用简单的参数约束即可。如果您这样更改它,您的测试将通过:

  def "Test success send message method"() {
    given:
    sendResult.getRecordMetadata() >> recordMetadata
//    kafkaTemplate.send(_ as String, _ as String) >> future

    when:
    kafkaService.sendMessage(topicName, message)

    then:
    // catch success or failed here.
    1 * kafkaTemplate.send(topicName, message) >> future
  }