Unit testing 为什么我的卡夫卡侦听器在我的单元测试中不工作
问题 我试图对发送整数的卡夫卡制作者进行单元测试。当运行单元测试时,我可以看到输出,表明我的生产者和消费者在控制台中工作正常。也就是说,生产者发送的值为零,消费者收到的值为零,并将该整数与运行的总和相加Unit testing 为什么我的卡夫卡侦听器在我的单元测试中不工作,unit-testing,spring-kafka,Unit Testing,Spring Kafka,问题 我试图对发送整数的卡夫卡制作者进行单元测试。当运行单元测试时,我可以看到输出,表明我的生产者和消费者在控制台中工作正常。也就是说,生产者发送的值为零,消费者收到的值为零,并将该整数与运行的总和相加 sending data = 0 received content = 0 sending total = 0 但是,当测试消费者记录返回空条目时,单元测试最终失败。我猜听众根本不工作 java.lang.AssertionError: Expected: a ConsumerRecord
sending data = 0
received content = 0
sending total = 0
但是,当测试消费者记录返回空条目时,单元测试最终失败。我猜听众根本不工作
java.lang.AssertionError:
Expected: a ConsumerRecord with value 0
but: is null
问题
我定义容器/messageListener的方式是否有错误?还是我的单元测试有更根本的问题
此url包含我的producer/config和consumer/config的代码。在那里查看它可能比在这里创建庞大的代码部分更容易
单元测试
package com.calculator;
/**
* Created by ian on 2/9/18.
*/
import com.calculator.kafka.services.KafkaProducer;
import com.calculator.kafka.services.KafkaConsumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.core.ProducerFactory;
import org.springframework.kafka.listener.KafkaMessageListenerContainer;
import org.springframework.kafka.listener.MessageListener;
import org.springframework.kafka.listener.config.ContainerProperties;
import org.springframework.kafka.test.rule.KafkaEmbedded;
import org.springframework.kafka.test.utils.ContainerTestUtils;
import org.springframework.kafka.test.utils.KafkaTestUtils;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertThat;
import static org.springframework.kafka.test.assertj.KafkaConditions.key;
import static org.springframework.kafka.test.hamcrest.KafkaMatchers.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class KafkaTest {
// in case I need to send some integers
private Integer i1 = 0;
private Integer i2 = 3;
private static final String SENDER_TOPIC = "input";
private List<Integer> l1;
@Autowired
private KafkaProducer producer;
@Autowired
private KafkaConsumer consumer;
private KafkaMessageListenerContainer<String, Integer> container;
private BlockingQueue<ConsumerRecord<String, Integer>> records;
private static final Logger LOGGER = LoggerFactory.getLogger(KafkaTest.class);
@ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, SENDER_TOPIC);
@Before
public void testTemplate() throws Exception {
// set up the Kafka consumer properties
Map<String, Object> consumerProperties = KafkaTestUtils.consumerProps("test-group", "false", embeddedKafka);
// create a Kafka consumer factory
DefaultKafkaConsumerFactory<String, Integer> consumerFactory = new DefaultKafkaConsumerFactory<>(consumerProperties);
// set the topic that needs to be consumed
ContainerProperties containerProperties = new ContainerProperties(SENDER_TOPIC);
// create a Kafka MessageListenerContainer
container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);
// create a thread safe queue to store the received message
records = new LinkedBlockingQueue<>();
// setup a Kafka message listener
container.setupMessageListener(new MessageListener<String, Integer>() {
@Override
public void onMessage(ConsumerRecord<String, Integer> record) {
LOGGER.debug("test-listener received message='{}'", record.toString());
records.add(record);
}
});
// start the container and underlying message listener
container.start();
// wait until the container has the required number of assigned partitions
ContainerTestUtils.waitForAssignment(container, embeddedKafka.getPartitionsPerTopic());
}
@After
public void tearDown() {
// stop the container
container.stop();
}
@Test
public void testSend() throws InterruptedException {
// send the message
producer.send(i1);
// check that the message was received
ConsumerRecord<String, Integer> received = records.poll(10, TimeUnit.SECONDS);
// Hamcrest Matchers to check the value
assertThat(received, hasValue(i1));
// AssertJ Condition to check the key
assertThat(received, hasKey(null));
}
}
package.com.calculator;
/**
*由ian于2018年2月9日创建。
*/
导入com.calculator.kafka.services.KafkaProducer;
导入com.calculator.kafka.services.KafkaConsumer;
导入org.apache.kafka.clients.consumer.ConsumerRecord;
导入org.junit.After;
导入org.junit.Before;
导入org.junit.ClassRule;
导入org.junit.Test;
导入org.junit.runner.RunWith;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.boot.test.context.SpringBootTest;
导入org.springframework.kafka.core.DefaultKafkaConsumerFactory;
导入org.springframework.kafka.core.DefaultKafkaProducerFactory;
导入org.springframework.kafka.core.KafkaTemplate;
导入org.springframework.kafka.core.ProducerFactory;
导入org.springframework.kafka.listener.KafkaMessageListenerContainer;
导入org.springframework.kafka.listener.MessageListener;
导入org.springframework.kafka.listener.config.ContainerProperties;
导入org.springframework.kafka.test.rule.kafkamebedded;
导入org.springframework.kafka.test.utils.ContainerTestUtils;
导入org.springframework.kafka.test.utils.KafkaTestUtils;
导入org.springframework.test.annotation.DirtiesContext;
导入org.springframework.test.context.junit4.SpringRunner;
导入java.util.List;
导入java.util.Map;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.LinkedBlockingQueue;
导入java.util.concurrent.TimeUnit;
导入静态org.junit.Assert.assertThat;
导入静态org.springframework.kafka.test.assertj.KafkaConditions.key;
导入静态org.springframework.kafka.test.hamcrest.KafkaMatchers.*;
@RunWith(SpringRunner.class)
@春靴测试
@肮脏的环境
公共级卡夫卡捷斯特{
//以防我需要发送一些整数
私有整数i1=0;
私有整数i2=3;
私有静态最终字符串发送者\u TOPIC=“input”;
私人名单l1;
@自动连线
私人卡夫卡制作人;
@自动连线
私人卡夫卡消费品;
卡夫卡专用集装箱;
私有阻塞队列记录;
私有静态最终记录器Logger=LoggerFactory.getLogger(KafkaTest.class);
@阶级规则
public static kafkamebedded embedded kafka=新的kafkamebedded(1,true,发送方\主题);
@以前
public void testTemplate()引发异常{
//设置卡夫卡消费者属性
Map consumerProperties=KafkaTestUtils.consumerProps(“测试组”,“假”,嵌入kafka);
//创建卡夫卡消费品工厂
DefaultKafkaConsumerFactory consumerFactory=新的DefaultKafkaConsumerFactory(consumerProperties);
//设置需要使用的主题
ContainerProperties ContainerProperties=新的ContainerProperty(发送者主题);
//创建Kafka MessageListenerContainer
容器=新的KafkaMessageListenerContainer(consumerFactory、containerProperties);
//创建线程安全队列以存储收到的消息
记录=新建LinkedBlockingQueue();
//设置卡夫卡消息侦听器
container.setupMessageListener(新MessageListener(){
@凌驾
信息公开无效(消费者记录记录){
debug(“测试侦听器收到的消息='{}',record.toString());
记录。添加(记录);
}
});
//启动容器和底层消息侦听器
container.start();
//等待容器具有所需数量的分配分区
ContainerTestUtils.waitForAssignment(容器,embeddedKafka.getPartitionsPerTopic());
}
@之后
公共无效拆卸(){
//停止容器
container.stop();
}
@试验
public void testSend()引发InterruptedException{
//发送消息
producer.send(i1);
//检查消息是否已收到
接收到的ConsumerRecord=记录。轮询(10,时间单位。秒);
//Hamcrest匹配器检查值
资产(已收到,具有价值(i1));
//AssertJ条件检查钥匙
资产(已接收,hasKey(null));
}
}
您需要使用正确的键/值序列化器/反序列化器。KTU分别为Integer/String设置,您需要String/Integer
您的测试用例的此修改版本有效
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class KafkaTest {
// in case I need to send some integers
private final Integer i1 = 0;
private final Integer i2 = 3;
private static final String SENDER_TOPIC = "input";
private List<Integer> l1;
private KafkaMessageListenerContainer<String, Integer> container;
private BlockingQueue<ConsumerRecord<String, Integer>> records;
private static final Logger LOGGER = LoggerFactory.getLogger(KafkaTest.class);
@ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, SENDER_TOPIC);
@Before
public void testTemplate() throws Exception {
// set up the Kafka consumer properties
Map<String, Object> consumerProperties = KafkaTestUtils.consumerProps("test-group", "false", embeddedKafka);
consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
// create a Kafka consumer factory
DefaultKafkaConsumerFactory<String, Integer> consumerFactory = new DefaultKafkaConsumerFactory<>(
consumerProperties);
// set the topic that needs to be consumed
ContainerProperties containerProperties = new ContainerProperties(SENDER_TOPIC);
// create a Kafka MessageListenerContainer
container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);
// create a thread safe queue to store the received message
records = new LinkedBlockingQueue<>();
// setup a Kafka message listener
container.setupMessageListener(new MessageListener<String, Integer>() {
@Override
public void onMessage(ConsumerRecord<String, Integer> record) {
LOGGER.debug("test-listener received message='{}'", record.toString());
records.add(record);
}
});
// start the container and underlying message listener
container.start();
// wait until the container has the required number of assigned partitions
ContainerTestUtils.waitForAssignment(container, embeddedKafka.getPartitionsPerTopic());
}
@After
public void tearDown() {
// stop the container
container.stop();
}
@Test
public void testSend() throws InterruptedException {
// send the message
Map<String, Object> producerProps = KafkaTestUtils.producerProps(embeddedKafka);
producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
ProducerFactory<String, Integer> pf = new DefaultKafkaProducerFactory<>(producerProps);
KafkaTemplate<String, Integer> template = new KafkaTemplate<>(pf);
template.send(SENDER_TOPIC, i1);
// check that the message was received
ConsumerRecord<String, Integer> received = records.poll(10, TimeUnit.SECONDS);
// Hamcrest Matchers to check the value
assertThat(received, hasValue(i1));
// AssertJ Condition to check the key
assertThat(received, hasKey(null));
System.out.println(received);
}
}
谢谢,这是一个开始,但是对于我写的制片人来说,这仍然不起作用。这是测试的最终目标,请尝试将我的制作人整合到测试中。我拥有的生产者使用:
configProps.put(ProducerConfig.KEY\u SERIALIZER\u CLASS\u CONFIG,StringSerializer.CLASS);configProps.put(ProducerConfig.VALUE\u SERIALIZER\u CLASS\u CONFIG,JsonSerializer.CLASS)代码>我尝试将我的消费者属性与之匹配,但仍然没有成功。请参阅我答案的编辑-您的制作人已连接到其他经纪人。连接制作人解决了我的问题。奇怪的是,当我更新Producer属性时,我得到了一个org.apache.kafka.common.error
@Configuration
public class KafkaProducerConfig {
@Value("${" + KafkaEmbedded.SPRING_EMBEDDED_KAFKA_BROKERS + ":localhost:9092}")
private String bootstrapServer;
@Bean
public ProducerFactory<String, Integer> producerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer);
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class);
return new DefaultKafkaProducerFactory<>(configProps);
}
@Bean
public KafkaTemplate<String, Integer> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@DirtiesContext
public class KafkaTest {
// in case I need to send some integers
private final Integer i1 = 42;
private final Integer i2 = 3;
private static final String SENDER_TOPIC = "input";
private List<Integer> l1;
@Autowired
private KafkaProducer producer;
private KafkaMessageListenerContainer<String, Integer> container;
private BlockingQueue<ConsumerRecord<String, Integer>> records;
private static final Logger LOGGER = LoggerFactory.getLogger(KafkaTest.class);
@ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, SENDER_TOPIC);
@Before
public void testTemplate() throws Exception {
// set up the Kafka consumer properties
Map<String, Object> consumerProperties = KafkaTestUtils.consumerProps("test-group", "false", embeddedKafka);
consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, IntegerDeserializer.class);
// create a Kafka consumer factory
DefaultKafkaConsumerFactory<String, Integer> consumerFactory = new DefaultKafkaConsumerFactory<>(
consumerProperties);
// set the topic that needs to be consumed
ContainerProperties containerProperties = new ContainerProperties(SENDER_TOPIC);
// create a Kafka MessageListenerContainer
container = new KafkaMessageListenerContainer<>(consumerFactory, containerProperties);
// create a thread safe queue to store the received message
records = new LinkedBlockingQueue<>();
// setup a Kafka message listener
container.setupMessageListener(new MessageListener<String, Integer>() {
@Override
public void onMessage(ConsumerRecord<String, Integer> record) {
LOGGER.debug("test-listener received message='{}'", record.toString());
records.add(record);
}
});
// start the container and underlying message listener
container.start();
// wait until the container has the required number of assigned partitions
ContainerTestUtils.waitForAssignment(container, embeddedKafka.getPartitionsPerTopic());
}
@After
public void tearDown() {
// stop the container
container.stop();
}
@Test
public void testSend() throws InterruptedException {
// send the message
producer.send(i1);
// check that the message was received
ConsumerRecord<String, Integer> received = records.poll(10, TimeUnit.SECONDS);
// Hamcrest Matchers to check the value
assertThat(received, hasValue(i1));
// AssertJ Condition to check the key
assertThat(received, hasKey(null));
System.out.println(received);
}
}
ConsumerRecord(topic = input, partition = 1, offset = 0, CreateTime = 1519487134283, checksum = 866641474, serialized key size = -1, serialized value size = 4, key = null, value = 42)