← Back to list

Testing Event-Driven APIs: The Pragmatic Pattern I Actually Ship

The producer test passed. The consumer test passed. The integration broke in production because the producer was emitting a field the…

Rishi Gaurav · 2026-06-25 14:19 · 0 claps · 4.0 min read
#api-testing #api-testing-tools #ai-testing #ai #software-testing
Open on Medium ↗
Wiki topics: RAG · RAG & Retrieval AI · AI · General

Testing Event-Driven APIs: The Pragmatic Pattern I Actually Ship

The producer test passed. The consumer test passed. The integration broke in production because the producer was emitting a field the consumer’s schema didn’t know about. Both tests were doing exactly what they were written to do.

That was the day I stopped believing that passing producer and consumer tests automatically meant a healthy integration.

Both teams had done their jobs.

The producer validated every event before publishing.

The consumer validated every event it received.

Every pipeline was green.

Yet production still failed.

The culprit wasn’t the business logic. It wasn’t Kafka. It wasn’t networking.

It was the contract between the two services.

Since then, I’ve stopped relying solely on integration testing for asynchronous systems and adopted a schema-first contract validation approach that I call the Schema-Pact Pattern.

It’s simple, language agnostic, and catches event drift long before deployment.

Why Two Passing Tests Can Still Ship a Broken Integration

REST APIs fail loudly.

A missing endpoint immediately returns an error.

Event-driven systems behave differently.

Events are published.

Consumers process them independently.

Neither side knows immediately whether the other still understands the contract.

Imagine this sequence:

Producer:

{
  "customerId": 101,
  "status": "ACTIVE",
  "tier": "Gold"
}

Consumer:

Read customerId
Read status
Ignore everything else

Everything works.

Months later the producer changes the event:

{
  "customerId": 101,
  "membershipTier": "Gold",
  "status": "ACTIVE"
}

The producer tests still pass.

The consumer tests still pass.

Production fails because the consumer still expects:

tier

Nobody noticed because both teams tested independently.

The integration contract silently drifted.

The Hidden Cost of Async Drift

Unlike REST APIs, asynchronous systems don’t provide immediate feedback.

Failures often appear:

  • Hours later
  • Several services downstream
  • After messages enter retry queues
  • Inside dead-letter topics

Debugging becomes significantly harder because the original producer has already completed successfully.

By the time someone notices, the original deployment may already be hours old.

The Schema-Pact Pattern — What It Is in 15 Lines

The solution is surprisingly simple.

Instead of validating events against fixtures, validate them against a shared schema.

Think of the schema as the single source of truth.

Producer
Shared Schema
Consumer

Every event must satisfy the schema.

Every consumer validates against the same schema.

Nobody validates against handcrafted JSON examples.

That small change removes an enormous amount of maintenance.

Producer Side: Emit Against Schema in the Contract Test

Producer tests shouldn’t merely verify that events are published.

They should verify that every published event conforms to the agreed schema.

A simplified workflow looks like:

Build Event
Validate Schema
Publish

If validation fails, publishing never happens.

The producer immediately knows it introduced a breaking change.

This shifts contract validation to the earliest possible point.

Consumer Side: Assert Against Schema, Not Against a Fixture

Many consumer tests look like this:

Load sample-event.json
Deserialize
Assert fields

The problem?

Fixtures age.

Schemas evolve.

Eventually fixtures stop representing reality.

Instead, consumers should:

Receive event

Validate schema

Process business logic

The fixture becomes secondary.

The schema becomes authoritative.

Now both producer and consumer reference exactly the same definition.

Why Fixtures Eventually Lie

Fixtures are snapshots.

Production evolves.

Fixtures usually don’t.

I’ve seen repositories containing fixtures that were over three years old.

The tests still passed.

The application no longer reflected production behavior.

Schema validation removes much of this maintenance burden.

The CI Step That Catches Field Drift Before Merge

The final piece is continuous verification.

Every pull request should trigger:

Producer Contract Test
Consumer Contract Test
Schema Compatibility Check
Merge

If either side introduces an incompatible schema change, the build fails immediately.

Developers receive feedback before deployment.

Not after.

This single CI step has prevented more integration failures than any end-to-end environment I’ve worked with.

Backward Compatibility Matters

Not every schema change is breaking.

Adding an optional field?

Usually safe.

Removing a required field?

Breaking.

Renaming properties?

Breaking.

Changing enum values?

Potentially breaking.

A good compatibility checker understands these rules automatically.

Instead of asking:

“Did the schema change?”

Ask:

“Did the schema change in a backward-compatible way?”

Those are very different questions.

Kafka Contract Testing Isn’t Just About Kafka

Although Kafka is the most common example, the same pattern applies to:

  • RabbitMQ
  • Azure Service Bus
  • Google Pub/Sub
  • Amazon SNS/SQS
  • NATS
  • Apache Pulsar

The messaging platform isn’t the problem.

Contract evolution is.

Whether events travel through Kafka topics or cloud queues, producers and consumers still need a shared understanding of event structure.

That’s why Kafka contract testing is really a broader discipline of event schema validation.

A Practical Workflow

The pattern I recommend looks like this:

Step 1

Define the event schema.

Step 2

Store schemas alongside application code.

Step 3

Validate producer output.

Step 4

Validate consumer input.

Step 5

Run compatibility checks during every pull request.

Step 6

Version schemas deliberately.

Notice what’s missing.

Large integration environments.

Most schema problems can be detected long before spinning up multiple services.

Integration Tests Still Matter

This isn’t an argument against integration testing.

Integration tests remain essential for validating:

  • Message routing
  • Infrastructure configuration
  • Retry behavior
  • Authentication
  • Network resilience

But they shouldn’t be your first line of defense against schema drift.

That’s the schema’s job.

Integration tests verify systems.

Schemas verify contracts.

Those responsibilities shouldn’t overlap.

Final Thoughts

Event-driven architectures make systems more scalable and resilient — but they also introduce a subtle challenge: producers and consumers evolve independently.

Passing unit tests aren’t enough.

Passing integration tests aren’t always enough either.

Without a shared contract, small schema changes can quietly accumulate until production becomes the first place anyone notices.

The Schema-Pact pattern provides a practical solution by making the schema — not sample events — the source of truth.

Producers validate what they emit.

Consumers validate what they receive.

CI verifies compatibility before merge.

The result is fewer production surprises, simpler maintenance, and greater confidence when evolving asynchronous systems.

If you’d like to explore this topic in more depth, including examples for Kafka, event versioning, and CI/CD implementation, here’s a longer walkthrough on testing event-driven microservices:

**https://totalshiftleft.ai/blog/testing-event-driven-microservices**

In event-driven systems, contracts matter just as much as code. Treating schemas as first-class citizens has been one of the highest-return improvements I’ve made to asynchronous API testing.


메타데이터
post_id
311396c828ea
slug
testing-event-driven-apis-the-pragmatic-pattern-i-actually-ship-311396c828ea
url
https://medium.com/@rga_23597/testing-event-driven-apis-the-pragmatic-pattern-i-actually-ship-311396c828ea
canonical_url
https://medium.com/@rga_23597/testing-event-driven-apis-the-pragmatic-pattern-i-actually-ship-311396c828ea
author_url
https://medium.com/@rga_23597
status
ok
fetched_at
2026-06-29 22:44:20