practice

Contract Testing

also called Consumer-Driven Contracts

Verifying that a provider satisfies what its consumers actually depend on, without deploying both together.

testingcontractsintegrationspotifyci

Definition

Each consumer declares the subset of a provider's API it actually uses — specific fields, specific response shapes, specific status codes. Those declarations form a contract that the provider verifies in its own pipeline. Neither side needs the other running.

The problem it solves

In a distributed estate you have two bad options for integration confidence. End-to-end tests requiring every service deployed together are slow, flaky, expensive, and reintroduce the coordinated release that services were meant to eliminate. Unit tests with mocks verify that your code works against your assumptions about the provider, which is precisely the thing that drifts.

Contract testing gives the confidence of integration testing with the independence of unit testing: the provider learns at build time that a change would break a named consumer, before anything is deployed.

What makes it work

  • Consumers publish only what they use. A contract asserting the whole response shape defeats the purpose — the provider can then never add or reorder anything.
  • Provider verification runs in the provider's pipeline and blocks the build. A contract that is checked nightly and reported to a dashboard will be ignored.
  • A broker holds contracts and deployment state, so the pipeline can answer the operational question: can I deploy this version to production given what is currently running there?
  • Contracts are generated from real consumer tests, not written by hand, or they document intentions rather than usage.

Industry example

Organisations with many autonomous teams shipping independently — the Spotify squad model being the best-known articulation — need integration confidence that does not require coordination, because coordination is exactly what autonomy was purchased to avoid.

The organisational insight is that contract testing converts a social problem into a build failure. Without it, "who depends on this field?" is answered by asking around, and the answer is incomplete. With it, the provider's pipeline answers definitively and immediately, and the consumer team learns before their service breaks rather than after.

That is why the practice tends to be adopted at the point where the number of teams makes informal communication unreliable — usually far earlier than people expect.

Failure scenarios

  • Contracts too broad, freezing the provider's response shape entirely.
  • Verification not blocking, so failures accumulate unread.
  • Contracts stale, kept for consumers that no longer exist, so the provider cannot evolve.
  • Treated as a substitute for all integration testing, when it verifies shape and semantics of the interaction, not end-to-end business behaviour.
  • Only applied to synchronous APIs, while the event schemas — which have exactly the same problem and more consumers — go ungoverned.

Trade-offs

Bought: independent deployment with real confidence, a definitive answer to "who depends on this", fast feedback. Sold: setup and maintenance effort, a broker to operate, and a discipline that decays quickly if verification is not enforced.

Interview question

"How would you know, before deploying, whether removing a response field will break anyone?"