Kafka ConsumerRecord返回null

时间:2018-04-17 18:27:06

标签: spring-boot spring-kafka

尝试在spring-boot应用程序中实现单元测试时,虽然使用自己的POJO的自定义Serializer正在运行,但我无法检索ConsumerRecord。我用kafka-console-consumer检查了它,每次都有一条新消息,每次我运行生成的测试并出现在控制台上。 我需要做些什么来获取记录而不是null

@RunWith(SpringRunner.class)
@SpringBootTest
@DisplayName("Testing GlobalMessageTest")
@DirtiesContext
public class NumberPlateSenderTest {

private static Logger log = LogManager.getLogger(NumberPlateSenderTest.class);

@Autowired
KafkaeskAdapterApplication kafkaeskAdapterApplication;

@Autowired
private NumberPlateSender numberPlateSender;

private KafkaMessageListenerContainer<String, NumberPlate> container;
private BlockingQueue<ConsumerRecord<String, NumberPlate>> records;

private static final String SENDER_TOPIC = "numberplate_test_topic";

@ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, SENDER_TOPIC);

@Before
public void setUp() throws Exception {
    // set up the Kafka consumer properties
    Map<String, Object> consumerProperties = KafkaTestUtils.consumerProps("sender", "false", embeddedKafka);
    consumerProperties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    consumerProperties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, NumberPlateDeserializer.class);


    // create a Kafka consumer factory
    DefaultKafkaConsumerFactory<String, NumberPlate> 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((MessageListener<String, NumberPlate>) record -> {
        log.info("Message 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());
}

@DisplayName("Should send a Message to a Producer and retrieve it")
@Test
public void TestProducer() throws InterruptedException {
    //Test instance of Numberplate to send
    NumberPlate localNumberplate = new NumberPlate();
    byte[] bytes = "0x33".getBytes();
    localNumberplate.setImageBlob(bytes);
    localNumberplate.setNumberString("ABC123");
    log.info(localNumberplate.toString());

    //Send it
    numberPlateSender.sendNumberPlateMessage(localNumberplate);

    //Retrieve it
    ConsumerRecord<String, NumberPlate> received = records.poll(3, TimeUnit.SECONDS);
    log.info("Received the following content of ConsumerRecord: {}", received);

    if (received == null) {
        assert false;
    } else {
        NumberPlate retrNumberplate = received.value();
        Assert.assertEquals(retrNumberplate, localNumberplate);
    }
}

@After
public void tearDown() {
    // stop the container
    container.stop();
}

}

我的github repository可以看到完整的代码。 我阅读了大量不同的SO问题并在网上搜索,但无法找到我的代码出错的方法。其他用户发布了类似的问题但无济于事。

在我的Craptop上运行的kafka版本 kafka_2.11-1.0.1

springframework kafka客户端的版本为 2.1.5.RELEASE

1 个答案:

答案 0 :(得分:2)

您的问题是您开始使用嵌入式 Kafka消费者,但是将数据发送到真实的那个。我不知道你的目标是什么,但是我让它反对像这样的嵌入式Kafka:

@BeforeClass
public static void setup() {
    System.setProperty("kafka.bootstrapAddress", embeddedKafka.getBrokersAsString());
}

我使用嵌入式Kafka提供的代理地址覆盖生产者的kafka.bootstrapAddress配置属性。

在这种情况下,我失败了:

java.lang.AssertionError: expected: dev.semo.kafkaeskadapter.models.NumberPlate<NumberPlate{numberString='ABC123', imageBlob=[48, 120, 51, 51]}> but was: dev.semo.kafkaeskadapter.models.NumberPlate<NumberPlate{numberString='ABC123', imageBlob=[48, 120, 51, 51]}>
Expected :dev.semo.kafkaeskadapter.models.NumberPlate<NumberPlate{numberString='ABC123', imageBlob=[48, 120, 51, 51]}> 
Actual   :dev.semo.kafkaeskadapter.models.NumberPlate<NumberPlate{numberString='ABC123', imageBlob=[48, 120, 51, 51]}>

但那只是因为你使用了这个断言:

Assert.assertEquals(retrNumberplate, localNumberplate);

同时,您的NumberPlate没有提供正确的equals()实施。像这样:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    NumberPlate that = (NumberPlate) o;
    return Objects.equals(numberString, that.numberString) &&
            Arrays.equals(imageBlob, that.imageBlob);
}

@Override
public int hashCode() {
    int result = Objects.hash(numberString);
    result = 31 * result + Arrays.hashCode(imageBlob);
    return result;
}

感谢您提供整个项目的播放和重现!使用&#34;问题 - 答案 - 问题 - 答案&#34;游戏我们会花太多时间在这里: - )。