我正在寻找一种测试 Kafka Streams 应用程序的方法。这样我就可以定义输入事件,并且测试套件会向我显示输出。
如果没有真正的 Kafka 设置,这可能吗?
我正在寻找一种测试 Kafka Streams 应用程序的方法。这样我就可以定义输入事件,并且测试套件会向我显示输出。
如果没有真正的 Kafka 设置,这可能吗?
更新Kafka 1.1.0(2018 年 3 月 23 日发布):
有一个
kafka-streams-test-utils
提供TopologyTestDriver
、ConsumerRecordFactory
和OutputVerifier
类的新工件。您可以将新工件作为常规依赖项包含到您的单元测试中,并使用测试驱动程序来测试您的 Kafka Streams 应用程序的业务逻辑。有关详细信息,请参阅KIP-247。
从文档中:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams-test-utils</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
测试驱动程序模拟库运行时,它不断地从输入主题中获取记录并通过遍历拓扑来处理它们。您可以使用测试驱动程序来验证您指定的处理器拓扑是否使用手动输入的数据记录计算出正确的结果。测试驱动程序捕获结果记录并允许查询其嵌入式状态存储:
// 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());
有关详细信息,请参阅文档。
ProcessorTopologyTestDriver
从 0.11.0.0 开始可用。它在kafka-streams
测试工件中可用(<classifier>test</classifier>
在 Maven 中指定):
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-streams</artifactId>
<version>0.11.0.0</version>
<classifier>test</classifier>
<scope>test</scope>
</dependency>
您还需要添加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>
然后就可以使用测试驱动了。根据 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);
您可以将输入输入到拓扑中,就好像您实际上已经写入了输入主题之一:
driver.process("input-topic", "key1", "value1", strSerializer, strSerializer);
并阅读输出主题:
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);
然后你可以断言这些结果。
当您询问是否可以在没有真正 Kafka 设置的情况下测试 Kafka Streams 应用程序时,您可以在 Scala 中尝试这个 Mocked Streams 库。Mocked Streams 1.0 是 Scala >= 2.11.8 的库,它允许您在没有 Zookeeper 和 Kafka Brokers 的情况下对 Kafka Streams 应用程序(因为 Apache Kafka >=0.10.1)的处理拓扑进行单元测试。参考:https ://github.com/jpzk/mockedstreams
您还可以使用 scalatest-embedded-kafka,它是一个库,提供内存中的 Kafka 代理来运行您的 ScalaTest 规范。它使用 Kafka 0.10.1.1 和 ZooKeeper 3.4.8。
参考:https ://github.com/manub/scalatest-embedded-kafka#scalatest-embedded-kafka-streams
祝你好运!
Spring kafka 支持使用嵌入式 kafka 进行单元测试,请参阅https://docs.spring.io/spring-kafka/docs/2.1.0.RELEASE/reference/html/_reference.html#__embeddedkafka_annotation。
此外,kafka 团队正在努力为流https://issues.apache.org/jira/browse/KAFKA-3625发布测试驱动程序。
你可以使用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
希望这可以帮助你...
您可以在本地运行单个 Zookeeper 和代理来测试 Kafka Streams 应用程序。
只需遵循这些快速入门指南:
另请查看此 Kafka Streams 示例(在 JavaDocs 中有详细的演练说明):
如果要测试使用 的Kafka Stream
拓扑,DmitryProcessor API
提供的代码可能无法正常工作。因此,在对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");
}
}
你应该在这里检查 Kafka Unit 。
您的测试设置应如下所示:
KafkaUnit kafkaUnitServer = new KafkaUnit();
kafkaUnitServer.startup();
kafkaUnitServer.createTopic(testTopic);
KeyedMessage<String, String> keyedMessage = new KeyedMessage<>(testTopic, "key", "value");
kafkaUnitServer.sendMessages(keyedMessage);
然后阅读您的消息并断言一切正常,您可以执行以下操作:
List<String> messages = kafkaUnitServer.readMessages(testTopic, 1);
这实际上启动了一个嵌入式 kafka,它可以帮助您将所需的一切都包含在测试中。
您可能会更花哨一点,并将嵌入式 kafka 设置为setup()
方法(或setupSpec()
在 Spock 中),然后将嵌入式 kafka 停止在teardown()
.