我在用 EmbeddedKafka
来自KafkaSpring测试,版本2.0.1.release(最新)。我有非常简单的测试,当只运行一个测试时,这些测试可以正常工作。但每当我一个接一个地运行它们(所以只运行整个测试类)时,第二个就失败了—使用者不会收到任何消息。
public class KafkaControllerTest {
private static final String FOO_TOPIC = "fooTopic";
@Rule
public KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, FOO_TOPIC);
MessageConsumer msgConsumerFoo = mock(MessageConsumer.class);
@Before
public void before() {
assertTrue(embeddedKafka.getBrokerAddresses().length == 1);
KafkaController controller = new KafkaController(
embeddedKafka.getBrokerAddress(0).toString(),
new Consumer(FOO_TOPIC, msgConsumerFoo));
MockMvcBuilders.standaloneSetup(controller).build();
}
@Test
public void kafkaFirstTest() throws Exception {
sendMessage(FOO_TOPIC, "foo message");
verify(msgConsumerFoo).consume(any());
}
@Test
public void kafkaSecondTest() throws Exception {
sendMessage(FOO_TOPIC, "foo2 message");
verify(msgConsumerFoo).consume(any());
}
void sendMessage(String topic, String notification) throws ExecutionException, InterruptedException {
Map<String, Object> props = KafkaTestUtils.producerProps(embeddedKafka);
Producer<Integer, String> producer = new DefaultKafkaProducerFactory<Integer, String>(props).createProducer();
producer.send(new ProducerRecord<>(topic, notification)).get();
}
}
测试等级和代码:
public class KafkaController {
public KafkaController(String brokerAddress, Consumer... consumers) {
for (Consumer consumer : consumers) {
addTopicListener(brokerAddress, consumer.topic, consumer.messageConsumer);
}
}
private void addTopicListener(String brokerAddress, String topic, MessageConsumer consumer) {
HashMap<String, Object> consumerConfig = new HashMap<>();
consumerConfig.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerAddress);
consumerConfig.put(ConsumerConfig.GROUP_ID_CONFIG, UUID.randomUUID().toString());
DefaultKafkaConsumerFactory<String, String> cf = new DefaultKafkaConsumerFactory<>(
consumerConfig,
new StringDeserializer(),
new StringDeserializer());
ContainerProperties containerProperties = new ContainerProperties(topic);
containerProperties.setMessageListener((MessageListener<String, String>) data -> {
consumer.consume(data.value());
});
ConcurrentMessageListenerContainer container = new ConcurrentMessageListenerContainer<>(cf, containerProperties);
container.start();
}
public interface MessageConsumer {
void consume(String message);
}
public static class Consumer {
private final String topic;
private final MessageConsumer messageConsumer;
public Consumer(String topic, MessageConsumer messageConsumer) {
this.topic = topic;
this.messageConsumer = messageConsumer;
}
}
}
我相信问题是由 KafkaEmbedded
因为消费者使用本地kafka示例测试的结果是正确的。
有什么我不知道的吗?我没有找到任何有帮助的消费品。
KafkaSpring测试医生说:
通常建议将规则用作@classrule,以避免在测试之间启动/停止代理(并为每个测试使用不同的主题)。
然而,我尝试了两种方法 KafkaEmbedded
作为 @ClassRule
在测试中使用不同的主题,但仍然一无所获。
此问题与异步性有关,因为在第二个测试中添加延迟有助于:
@Test
public void kafkaSecondTest() throws Exception {
Thread.sleep(1000);
sendMessage(FOO_TOPIC, "foo2 message");
Thread.sleep(1000);
verify(msgConsumerFoo).consume(any());
}
是的,不知何故,只有在 Thread.sleep(1000)
在发送消息之前和之后添加。
那我怎么检查 KafkaEmbedded
或者其他组件已准备好发送/使用消息?
1条答案
按热度按时间jmp7cifd1#
你可能需要
auto.offset.reset=earliest
(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG
). 否则,您可能会在容器完全启动之前发送消息。当然,如果您使用相同的主题,第二个消费者应该会收到两条消息。
另外,我建议在每个测试结束时停止容器。调试日志也应该有帮助。
编辑
另一种方法是使用
ContainerTestUtils.waitForAssignment()
在测试中发送消息之前;我们在框架测试中经常这样做。