问题
I'm trying to unit test the callbacks from the kafkaTemplate.send() but its not working as expected. here's the code snippet of the code im trying to test.
@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")
}
});
}
and this is the unit test code
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
}
}
based on the debugger future is null on this scenario
ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send(topicName, message); // future null
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() { // future null
i already read a lot of answers here but it does not solved the issue or havent they explain it well that i would understand where the problem is. like this one https://stackoverflow.com/a/56677098
thanks for the help in advance!
回答1:
You are making a typical Spock beginner's mistake when trying to combine mocking and stubbing: First declare a stub result in the given: block and later a checked mock interaction (without stub result) in the then: block. But mocking and stubbing always have to happen in the same interaction as described in the manual chapter I linked to. The manual also explains that the interaction in the then: block wins in your case, i.e. because you do not specify a stub result there, the result will default to null.
Furthermore, you make the argument verification much more difficult than necessary. Just use simple argument constraints instead. Your test will pass if you change it like this:
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
}
回答2:
Since you are mocking the KafkaTemplate; you need to mock the send method to return a future.
I am not familiar with Spock.
With Mockito, this would be
SettableListenerFuture<SendResult<?, ?>> future = new SettableListenerFuture<>();
given(template.send(anyString(), anyString())).willReturn(future);
来源:https://stackoverflow.com/questions/61100974/unit-testing-listenablefuture-kafkatemplate-send-always-returns-null