对使用kstream联接的kafka拓扑进行单元测试

时间:2019-03-08 12:55:44

标签: java unit-testing join apache-kafka

我有一个做两个kstream连接的拓扑,面临的问题是当尝试使用TopologyTestDriver进行单元测试时,先使用pipeInput发送几个ConsumerRecords,然后使用readOutput。似乎没有用。

我认为这可能是因为联接使用的是实际kafka中的内部rocksdb,而我们在测试中并未使用

所以我一直在寻找解决方案,但是找不到任何解决方法。

注意:删除kstream-kstream联接时,这种测试方法可以很好地工作。

2 个答案:

答案 0 :(得分:4)

我有一个执行两个kstream联接的拓扑,面临的问题是当尝试使用TopologyTestDriver进行单元测试时,先使用pipeInput发送几个ConsumerRecords,然后再发送readOutput。看来没有用。

根据设计,但不幸的是,TopologyTestDriver并不是Kafka Streams引擎在运行时如何工作的100%准确的模型。值得注意的是,新的传入事件的处理顺序有所不同。

这确实会在尝试测试某些连接时引起问题,例如某些连接,因为这些操作取决于特定的处理顺序(例如,在流表连接中,该表之前应该已经有键“ alice”的条目)流“ alice”的流端事件到达,否则流端“ alice”的联接输出将不包含任何表端数据。

因此,我一直在寻找解决方案,但找不到任何解决方法。

我建议使用的测试会旋转嵌入式Kafka集群,然后使用“真实的” Kafka Streams引擎(即,不是TopologyTestDriver)对该集群运行测试。有效地,这意味着您要将测试从单元测试更改为集成/系统测试:您的测试将启动成熟的Kafka Streams拓扑,该拓扑与与测试在同一台计算机上运行的嵌入式Kafka集群通信。

请参阅Apache Kafka项目中的Kafka Streams集成测试,其中EmbeddedKafkaClusterIntegrationTestUtils是工具的核心部分。联接的一个具体测试示例是StreamTableJoinIntegrationTest(有一些与联接相关的集成测试)及其父级AbstractJoinIntegrationTest。 (就其价值而言,https://github.com/confluentinc/kafka-streams-examples#examples-integration-tests上还有更多的集成测试示例,其中包括使用Apache Avro作为数据格式等时还涉及Confluent Schema Registry的测试。)

但是,除非我没有记错,否则集成测试及其工具 不会包含在Kafka Streams的test utilities工件(即org.apache.kafka:kafka-streams-test-utils)中。因此,您必须将复制粘贴到自己的代码库中。

答案 1 :(得分:2)

您是否看过Ka​​fka Streams单元测试[1]?这是关于管道传输数据并使用模拟处理器检查最终结果的方法。

例如以下流加入:

        stream1 = builder.stream(topic1, consumed);
        stream2 = builder.stream(topic2, consumed);
        joined = stream1.outerJoin(
            stream2,
            MockValueJoiner.TOSTRING_JOINER,
            JoinWindows.of(ofMillis(100)),
            StreamJoined.with(Serdes.Integer(), Serdes.String(), Serdes.String()));
        joined.process(supplier);

然后,您可以开始将输入项传递到第一个或第二个主题中,并检查每个连续的输入传递,处理器可以检查什么:

// push two items to the primary stream; the other window is empty
            // w1 = {}
            // w2 = {}
            // --> w1 = { 0:A0, 1:A1 }
            //     w2 = {}
            for (int i = 0; i < 2; i++) {
                inputTopic1.pipeInput(expectedKeys[i], "A" + expectedKeys[i]);
            }
            processor.checkAndClearProcessResult(EMPTY);

            // push two items to the other stream; this should produce two items
            // w1 = { 0:A0, 1:A1 }
            // w2 = {}
            // --> w1 = { 0:A0, 1:A1 }
            //     w2 = { 0:a0, 1:a1 }
            for (int i = 0; i < 2; i++) {
                inputTopic2.pipeInput(expectedKeys[i], "a" + expectedKeys[i]);
            }
            processor.checkAndClearProcessResult(new KeyValueTimestamp<>(0, "A0+a0", 0),
                new KeyValueTimestamp<>(1, "A1+a1", 0));

我希望这会有所帮助。

参考: [1] https://github.com/apache/kafka/blob/trunk/streams/src/test/java/org/apache/kafka/streams/kstream/internals/KStreamKStreamJoinTest.java#L279