简体   繁体   English

测试 Kafka Streams 拓扑

[英]Test Kafka Streams topology

I'm searching a way to test a Kafka Streams application.我正在寻找一种测试 Kafka Streams 应用程序的方法。 So that I can define the input events and the test suite shows me the output.这样我就可以定义输入事件,并且测试套件向我显示输出。

Is this possible without a real Kafka setup?如果没有真正的 Kafka 设置,这可能吗?

Update Kafka 1.1.0 (released 23-Mar-2018):更新Kafka 1.1.0(2018 年 3 月 23 日发布):

KIP-247 added official test utils. KIP-247添加了官方测试工具。 Per the Upgrade Guide :根据升级指南

There is a new artifact kafka-streams-test-utils providing a TopologyTestDriver , ConsumerRecordFactory , and OutputVerifier class.有一个新的工件kafka-streams-test-utils提供了TopologyTestDriverConsumerRecordFactoryOutputVerifier类。 You can include the new artifact as a regular dependency to your unit tests and use the test driver to test your business logic of your Kafka Streams application.您可以将新工件作为常规依赖项包含在单元测试中,并使用测试驱动程序来测试 Kafka Streams 应用程序的业务逻辑。 For more details, see KIP-247 .有关更多详细信息,请参阅KIP-247

From the documentation :文档

    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-streams-test-utils</artifactId>
        <version>1.1.0</version>
        <scope>test</scope>
    </dependency>

The test driver simulates the library runtime that continuously fetches records from input topics and processes them by traversing the topology.测试驱动程序模拟库运行时不断从输入主题中获取记录并通过遍历拓扑来处理它们。 You can use the test driver to verify that your specified processor topology computes the correct result with the manually piped in data records.您可以使用测试驱动程序来验证您指定的处理器拓扑是否通过手动输入的数据记录计算出正确的结果。 The test driver captures the results records and allows to query its embedded state stores:测试驱动程序捕获结果记录并允许查询其嵌入的状态存储:

    // Create your topology
    Topology topology = new Topology();
    Properties config = new Properties();
    config.put(StreamsConfig.APPLICATION_ID_CONFIG, "test");
    config.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "dummy:1234");

    // Run it on the test driver
    TopologyTestDriver testDriver = new TopologyTestDriver(topology, config);

    // Feed input data
    ConsumerRecordFactory<String, Integer> factory = new ConsumerRecordFactory<>("input-topic", new StringSerializer(), new IntegerSerializer());
    testDriver.pipe(factory.create("key", 42L));

    // Verify output
    ProducerRecord<String, Integer> outputRecord = testDriver.readOutput("output-topic", new StringDeserializer(), new LongDeserializer());

See the documentation for details.有关详细信息,请参阅文档


ProcessorTopologyTestDriver is available as of 0.11.0.0. ProcessorTopologyTestDriver从 0.11.0.0 开始可用。 It is available in the kafka-streams test artifact (specified with <classifier>test</classifier> in Maven):它在kafka-streams测试工件中可用(在 Maven 中用<classifier>test</classifier>指定):

    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-streams</artifactId>
        <version>0.11.0.0</version>
        <classifier>test</classifier>
        <scope>test</scope>
    </dependency>

You will also need to add the kafka-clients test artifact:您还需要添加kafka-clients测试工件:

    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>0.11.0.0</version>
        <classifier>test</classifier>
        <scope>test</scope>
    </dependency>

Then you can use the test driver.然后就可以使用测试驱动了。 Per the Javadoc, first create a ProcessorTopologyTestDriver :根据 Javadoc,首先创建一个ProcessorTopologyTestDriver

    StringSerializer strSerializer = new StringSerializer();
    StringDeserializer strDeserializer = new StringDeserializer();
    Properties props = new Properties();
    props.setProperty(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9091");
    props.setProperty(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, CustomTimestampExtractor.class.getName());
    props.setProperty(StreamsConfig.KEY_SERIALIZER_CLASS_CONFIG, strSerializer.getClass().getName());
    props.setProperty(StreamsConfig.KEY_DESERIALIZER_CLASS_CONFIG, strDeserializer.getClass().getName());
    props.setProperty(StreamsConfig.VALUE_SERIALIZER_CLASS_CONFIG, strSerializer.getClass().getName());
    props.setProperty(StreamsConfig.VALUE_DESERIALIZER_CLASS_CONFIG, strDeserializer.getClass().getName());
    StreamsConfig config = new StreamsConfig(props);
    TopologyBuilder builder = ...
    ProcessorTopologyTestDriver driver = new ProcessorTopologyTestDriver(config, builder);

You can feed input into the topology as though you had actually written to one of the input topics:您可以将输入输入到拓扑中,就像您实际写入输入主题之一一样:

    driver.process("input-topic", "key1", "value1", strSerializer, strSerializer);

And read output topics:并阅读输出主题:

    ProducerRecord<String, String> record1 = driver.readOutput("output-topic-1", strDeserializer, strDeserializer);
    ProducerRecord<String, String> record2 = driver.readOutput("output-topic-1", strDeserializer, strDeserializer);
    ProducerRecord<String, String> record3 = driver.readOutput("output-topic-2", strDeserializer, strDeserializer);

Then you can assert on these results.然后你可以对这些结果进行断言。

  1. As you are asking if it is possible to test Kafka Streams application without a real Kafka setup, you might try this Mocked Streams library in Scala.当您问是否可以在没有真正的 Kafka 设置的情况下测试 Kafka Streams 应用程序时,您可以在 Scala 中尝试这个 Mocked Streams 库。 Mocked Streams 1.0 is a library for Scala >= 2.11.8 which allows you to unit-test processing topologies of Kafka Streams applications (since Apache Kafka >=0.10.1) without Zookeeper and Kafka Brokers. Mocked Streams 1.0 是一个适用于 Scala >= 2.11.8 的库,它允许您在没有 Zookeeper 和 Kafka Brokers 的情况下对 Kafka Streams 应用程序(因为 Apache Kafka >=0.10.1)的处理拓扑进行单元测试。 Reference: https://github.com/jpzk/mockedstreams参考: https : //github.com/jpzk/mockedstreams

  2. You can also use scalatest-embedded-kafka which is a library that provides an in-memory Kafka broker to run your ScalaTest specs against.您还可以使用 scalatest-embedded-kafka,它是一个库,提供内存中的 Kafka 代理来运行您的 ScalaTest 规范。 It uses Kafka 0.10.1.1 and ZooKeeper 3.4.8.它使用 Kafka 0.10.1.1 和 ZooKeeper 3.4.8。
    Reference: https://github.com/manub/scalatest-embedded-kafka#scalatest-embedded-kafka-streams参考: https : //github.com/manub/scalatest-embedded-kafka#scalatest-embedded-kafka-streams

Good luck!祝你好运!

Spring kafka has support for unit testing with an embedded kafka see https://docs.spring.io/spring-kafka/docs/2.1.0.RELEASE/reference/html/_reference.html#__embeddedkafka_annotation . Spring kafka 支持使用嵌入式 kafka 进行单元测试,请参阅https://docs.spring.io/spring-kafka/docs/2.1.0.RELEASE/reference/html/_reference.html#__embeddedkafka_annotation

Also the kafka team is working on releasing a test driver for streams https://issues.apache.org/jira/browse/KAFKA-3625 .此外,kafka 团队正在努力为流https://issues.apache.org/jira/browse/KAFKA-3625发布测试驱动程序。

You can just run a single Zookeeper and broker locally to test a Kafka Streams application.您可以只在本地运行一个 Zookeeper 和代理来测试 Kafka Streams 应用程序。

Just follow those quick start guides:只需遵循这些快速入门指南:

Also check out this Kafka Streams examples (with detailed walk through instructions in the JavaDocs):另请查看此 Kafka Streams 示例(在 JavaDocs 中有详细的演练说明):

You should check Kafka Unit here .您应该在此处查看 Kafka Unit。

Your test setup should look something like this:您的测试设置应如下所示:

KafkaUnit kafkaUnitServer = new KafkaUnit();
kafkaUnitServer.startup();
kafkaUnitServer.createTopic(testTopic);
KeyedMessage<String, String> keyedMessage = new KeyedMessage<>(testTopic, "key", "value");
kafkaUnitServer.sendMessages(keyedMessage);

And then to read your messages and assert that everything went ok you do something like this:然后阅读您的消息并断言一切正常,您可以执行以下操作:

List<String> messages = kafkaUnitServer.readMessages(testTopic, 1);

This actually spins up an embedded kafka that helps you have everything you need contained in a test.这实际上会启动一个嵌入式 kafka,帮助您在测试中包含所需的一切。

You could get a little bit fancier and setup your embedded kafka as a setup() method (or setupSpec() in Spock) and stop your embedded kafka in a teardown() .您可以更高级一点,将嵌入式 kafka setup()setup()方法(或 Spock 中的setupSpec() ),然后在teardown()停止嵌入式 kafka。

you can use https://github.com/jpzk/mockedstreams see the example below...你可以使用https://github.com/jpzk/mockedstreams看下面的例子...

import com.madewithtea.mockedstreams.MockedStreams

val input = Seq(("x", "v1"), ("y", "v2"))
val exp = Seq(("x", "V1"), ("y", "V2"))
val strings = Serdes.String()

MockedStreams()
  .topology { builder => builder.stream(...) [...] }
  .input("topic-in", strings, strings, input)
  .output("topic-out", strings, strings, exp.size) shouldEqual exp

hope this helps you...希望这对你有帮助...

If you want to test a Kafka Stream Topology that uses Processor API , the code provided by Dmitry may not work properly.如果要测试使用Processor APIKafka Stream Topology, Dmitry提供的代码可能无法正常工作。 So after a few hours of researching in the Javadocs and official docs I came out with a working code in order to test a custom processor that you have implemented using JUnit .因此,在对Javadocs官方文档进行了几个小时的研究后,我得出了一个工作代码,以测试您使用JUnit实现的自定义处理器。

public class TopologySpec {

private TopologyTestDriver testDriver;

@Before
public void setup() {
    // Processor API
    Topology topology = new Topology();
    topology.addSource("sourceProcessor", "input-topic");
    // In this case, 'EventProcessor' is a custom processor
    // that I implemented and I want to test
    topology.addProcessor("processor", EventProcessor::new, "sourceProcessor");
    topology.addSink("sinkProcessor", "output-topic", "processor");

    // Setup test driver
    Properties config = new Properties();
    config.put(StreamsConfig.APPLICATION_ID_CONFIG, "test");
    config.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "dummy:1234");
    // EventProcessor is a <String,String> processor 
    // so we set those serders
    config.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
    config.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());
    testDriver = new TopologyTestDriver(topology, config);
}

@After
public void tearDown() {
    testDriver.close(); // Close processors after finish the tests
}

@Test
public void firstTest() {
    // Simulate a producer that sends the message "value,val" without key
    ConsumerRecordFactory factory =
            new ConsumerRecordFactory(new StringSerializer(), new StringSerializer());

    testDriver.pipeInput(factory.create("input-topic", "value,val"));

    // Simulate a consumer that reads from the output topic 
    // where are supposed to be the messages after being processed
    // by your custom processor
    ProducerRecord<String, String> record1 =
            testDriver.readOutput("output-topic", new StringDeserializer(), new StringDeserializer());

    // Compare the output to ensure that your custom processor
    // is working properly. In this case, my processor consumes
    // the message, concatenates ":::processed" to it, and
    // push it to the output-topic
    OutputVerifier.compareValue(record1, "value,val:::processed");
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM