Unravel › Java concepts › Testing
Testing Kafka code
Kafka code is tested at three levels: unit tests with mock producers and consumers, topology tests for Kafka Streams without a broker, and integration tests against a real broker started by the test (embedded or in a container).
Learn these first
At a glance
Testing a mail system: first with a pretend mailbox on the desk (mock), then with a small real post office built just for the test (embedded or container), never with the real national mail.
- 1MockProducer records everything sent to it, so a unit test asserts producer.history() without any networkMockConsumer is fed records with addRecord and schedulePollTask.
- 2TopologyTestDriver runs a Kafka Streams topology in memory: pipe in a TestInputTopic, read results from a TestOutputTopic, and inspect state storesNo broker is needed.
- 3@EmbeddedKafka (spring-kafka-test) starts a broker in the same JVM for a Spring test; Testcontainers KafkaContainer starts the real image and is closer to production
- 4Integration tests wait for asynchronous results with a bounded timeout (Awaitility) instead of Thread.sleep
- Use unique topic names and consumer group ids per test, or a @DirtiesContext, so tests do not read each other leftover messages
- Test the failure paths on purpose: a poison message that cannot be deserialized, a processing exception, a rebalance
- The embedded broker is the real Kafka server code started in-process with a temporary log directory
MockProducer<String, String> producer = new MockProducer<>(true, new StringSerializer(), new StringSerializer());OrderPublisher publisher = new OrderPublisher(producer);publisher.publish(new Order("o-1", "c-7"));assertEquals(1, producer.history().size());assertEquals("orders", producer.history().get(0).topic());- line 1 uses MockProducer, the core of Testing Kafka code
Read the full explanation (about 2 min)
Kafka code is tested at three levels: unit tests with mock producers and consumers, topology tests for Kafka Streams without a broker, and integration tests against a real broker started by the test (embedded or in a container).
A mental model
Testing a mail system: first with a pretend mailbox on the desk (mock), then with a small real post office built just for the test (embedded or container), never with the real national mail.
How it works
MockProducer records everything sent to it, so a unit test asserts producer.history() without any network. MockConsumer is fed records with addRecord and schedulePollTask.
TopologyTestDriver runs a Kafka Streams topology in memory: pipe in a TestInputTopic, read results from a TestOutputTopic, and inspect state stores. No broker is needed.
@EmbeddedKafka (spring-kafka-test) starts a broker in the same JVM for a Spring test; Testcontainers KafkaContainer starts the real image and is closer to production.
Integration tests wait for asynchronous results with a bounded timeout (Awaitility) instead of Thread.sleep.
Going deeper
Use unique topic names and consumer group ids per test, or a @DirtiesContext, so tests do not read each other leftover messages. Shared brokers are a source of flaky tests.
Test the failure paths on purpose: a poison message that cannot be deserialized, a processing exception, a rebalance. They are the cases that hurt in production.
A mock cannot show broker behaviour such as partition ordering, transactions or compaction. Keep a few container-based tests for those.
Under the hood
The embedded broker is the real Kafka server code started in-process with a temporary log directory. MockProducer implements the Producer interface by storing records in a list and completing futures immediately or on demand, so error callbacks can be triggered with errorNext.
Common mistakes
Thread.sleepwaits in tests.- Shared topics and group ids between tests.
- Testing only the happy path.
- Relying on mocks for ordering and transaction behaviour.
How Unravel recognises it
When you paste code, Unravel looks for these signs of testing kafka code. Spotting them yourself is a good habit when you read unfamiliar code:
- Annotations:
@EmbeddedKafka@AutoConfigureEmbeddedKafka - Types:
EmbeddedKafkaBrokerMockProducerMockConsumerTestInputTopicTestOutputTopicTopologyTestDriverKafkaTestUtilsEmbeddedKafkaKraftBrokerKafkaContainerConfluentKafkaContainerConsumerRecordMetadata
Part of a learning path
- Kafka beyond the basics · previous: Kafka Connect connectors
- Testing enterprise code · previous: Faking remote services (WireMock, MockWebServer, Pact)
Related concepts
Frequently asked questions
What is Testing Kafka code?
Kafka code is tested at three levels: unit tests with mock producers and consumers, topology tests for Kafka Streams without a broker, and integration tests against a real broker started by the test (embedded or in a container).
What are the most common mistakes with Testing Kafka code?
Thread.sleep waits in tests. Shared topics and group ids between tests. Testing only the happy path. Relying on mocks for ordering and transaction behaviour.
How can I see Testing Kafka code in real code?
Paste your own Java into Unravel and it will point out where testing kafka code appears, explain how it works at the detail level you choose, and draw the flow of the code around it.