Kafka testing for Spring Boot

Tap into every message your Kafka tests send.

Wiretap is a first-class testing library for Spring Boot and Spring Kafka. One shared embedded broker, declarative topics and seeding, listener-readiness, and fluent record assertions — the boilerplate around @EmbeddedKafka gone. Flip one property and the same tests run against Testcontainers or a live cluster.

Current
v5.2.3
Java
17+
Spring Boot
4.0+
Spring Kafka
4.0+
pom.xml
<dependency>
    <groupId>io.typecheck</groupId>
    <artifactId>wiretap-spring-boot</artifactId>
    <version>5.2.3</version>
    <scope>test</scope>
</dependency>

First-class Spring Kafka support

Built for @SpringBootTest and Spring Kafka 4 — your real beans, listeners, and KafkaTemplate, wired to a shared broker with automatic cleanup and assertions that read like sentences. One annotation, no test-harness boilerplate.

Getting started

Testcontainers & live-broker interoperable

Embedded is the fast default, not a cage. Set wiretap.test.mode=passthrough and the same suite runs against a Testcontainers broker or a running cluster — no rewrite. Seeding, cleanup, and every assertion behave identically against real Kafka.

Pass-through mode

Start with one annotation.

Configure topics, annotate the test class, then use your normal Spring beans alongside the shared broker and assertion helpers.

  • One shared embedded Kafka broker per test JVM
  • Pass-through mode: the same suite against Testcontainers or a local broker
  • Declarative seeding from .json and .ndjson fixtures, with ${placeholder} support
  • Automatic topic and consumer-group cleanup between tests
  • Mock Schema Registry support for Avro and Protobuf tests
  • Publisher, reader, listener-readiness, and assertion helpers
OrderFlowIT.java
@SpringBootTest
@EnableWiretapKafkaBroker(topics = "orders")
class OrderFlowIT {

    @Test
    void publishesOrderEvent() {
        KafkaTestPublisher.send("orders", "order-123",
            new OrderEvent("order-123", "cust-7", "CREATED", 4299),
            Map.of("X-Correlation-Id", "corr-123", "X-Source", "checkout"));

        assertThatTopic("orders")
            .hasRecordCount(1)
            .containsRecordSatisfying(OrderEvent.class, r -> r
                .hasKey("order-123")
                .hasHeaderWithValue("X-Source", "checkout")
                .hasJsonPath("$.customerId", "cust-7")
                .hasJsonPath("$.status", "CREATED"));
    }
}