我使用Java和Mockito模拟单元测试的一些方法。我想在下面的代码中模拟生产者,这样我就可以测试抛出异常时发送的日志消息。我试着嘲笑未来,但我得到的错误是future.get()方法不能被嘲笑,RecordMetadata
类是最终的,不能被嘲笑。如有任何帮助,我将不胜感激。
下例中的生产者为KafkaProducer
。
public void send(Log log){
Future<RecordMetadata> future = producer.send(new ProducerRecord<(this.topic, record));
try {
RecordMetadata recordMetadata = send.get();
} catch (InterruptedException e) {
LOG.error("Sending the message to kafka was interrupted. "+e);
}
}
Kafka提供了一个MockProducer
类,你可以将它注入到你的类中进行测试。可以在JUnit @Before
注释的设置方法中将类中的producer
设置为MockProducer
的实例。MockProducer
的参考文档:
一个模拟的生产者接口,可以用来测试使用Kafka的代码。
默认情况下,此模拟将成功同步完成每个send调用。然而,它可以被配置为允许用户控制调用的完成,并为生产者提供一个可选的错误来抛出。
您可以使用#errorNext
方法来提供您想要在测试场景中抛出的异常。
在没有看到测试代码的情况下很难做到精确。两个问题
1) RecordMetadata不能用于Mockito模拟,这是Mockito已知的限制。相反,您可以使用RecordMetadata的公共构造函数创建一个虚拟实例。
2) KafkaProducer可以被Mockito模拟,但是你需要一个两阶段的方法。首先,模拟KafkaProducer返回一个Future,其次,Future也是一个模拟,返回一些已知的值。
public class ServiceTest {
@Mock
private KafkaProducer<String, Integer> producer;
@Mock
private Future<RecordMetadata> future;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void success() throws Exception {
RecordMetadata dummyRecord = new RecordMetadata(null, 0L, 0L, 0L, 0L, 0, 0);
when(producer.send(any())).thenReturn(future);
when(future.get()).thenReturn(dummyRecord);
producer.send(null);
}
@Test
public void timeout() throws Exception {
when(producer.send(any())).thenReturn(future);
when(future.get()).thenThrow(new TimeoutException("timeout"));
producer.send(null);
}
}