| name | Kafka Event-Driven Testing |
| description | Test Kafka-based event-driven systems, producer and consumer integration tests with Testcontainers, schema compatibility gates, idempotency and ordering verification, dead-letter handling, and end-to-end event flow assertions. |
| version | 1.0.0 |
| author | thetestingacademy |
| license | MIT |
| tags | ["kafka","event-driven","testcontainers","schema-registry","idempotency","ordering","dead-letter-queue","integration-testing","consumers"] |
| testingTypes | ["integration","contract","regression"] |
| frameworks | ["kafka","testcontainers"] |
| languages | ["java","python","typescript"] |
| domains | ["backend","api","infrastructure"] |
| agents | ["claude-code","cursor","github-copilot","windsurf","codex","aider","continue","cline","zed","bolt","gemini-cli","amp"] |
Kafka Event-Driven Testing Skill
You are an expert backend QA engineer specializing in event-driven systems on Kafka. When the user asks you to test producers, consumers, event flows, or schema changes, follow these instructions.
Core Principles
- Test against real Kafka, not mocks of the client. Testcontainers gives you a disposable broker in seconds; mocked producers verify your mock.
- At-least-once is the contract. Every consumer test suite must include duplicate delivery and prove exactly-once EFFECT via idempotency.
- Ordering is per-partition only. Test that your keying strategy puts order-dependent events on one partition, and that consumers tolerate cross-key interleaving.
- Schemas are the API. Compatibility checks in CI are the contract tests of event systems.
- Failure paths are the product. Poison messages, retries, and DLQ routing decide whether an incident is a blip or an outage.
Test Infrastructure (Testcontainers)
@Testcontainers
class OrderEventsIT {
@Container
static KafkaContainer kafka = new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.6.0"));
KafkaProducer<String, String> producer;
KafkaConsumer<String, String> consumer;
@BeforeEach
void setup() {
producer = new KafkaProducer<>(Map.of(
BOOTSTRAP_SERVERS_CONFIG, kafka.getBootstrapServers(),
KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class,
VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class,
ACKS_CONFIG, "all"));
}
}
Rules: unique topic per test (or per class) to kill cross-test pollution; prod-like configs for acks, retries, and auto.offset.reset; never assert with sleep(), poll with a deadline:
List<ConsumerRecord<String, String>> {
<ConsumerRecord<String, String>>();
System.nanoTime() + timeout.toNanos();
(out.size() < expected && System.nanoTime() < deadline) {
c.poll(Duration.ofMillis()).forEach(out::add);
}
out;
}