practice

Software Contract Tests

Verifying an interaction between two components from both sides independently, so integration confidence does not require deploying both.

contract-testingintegrationcideploymentverification

Definition

A contract records what a consumer expects of a provider. The consumer verifies its code against the contract; the provider verifies its implementation against the same contract. Neither needs the other running, and a breaking change fails a build rather than an environment.

Why this is the load-bearing test level in a distributed system

The alternative options are both poor. End-to-end tests require every service deployed together — slow, flaky, and a reintroduction of the coordinated release that services were meant to eliminate. Mocks verify 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, which is why it is the level that makes independent deployment safe.

What makes it work

  • Consumers declare only what they use. A contract asserting the whole response shape freezes the provider entirely, which is worse than no contract.
  • Provider verification blocks the build. A check that runs nightly and posts to a dashboard is ignored within a month.
  • A broker holding contracts and deployment state, so the pipeline can answer the operational question: can I deploy this version given what is currently in production?
  • Contracts generated from real consumer tests, not hand-written, or they document intentions rather than usage.
  • Stale contracts removed when a consumer retires, or the provider is frozen by a service that no longer exists.

The gap most organisations leave

Contract testing is applied to synchronous APIs and event schemas are left ungoverned, even though published events have the same problem with more consumers and less visibility. The equivalent mechanism there is a schema registry with compatibility rules enforced in CI, and the reasoning is identical.

What it does not cover

Behaviour. A contract verifies the shape and semantics of an interaction, not that the overall business flow is correct. A handful of end-to-end tests for critical journeys remains necessary, and contract tests are what allow that handful to stay small.

Failure scenarios

  • Over-broad contracts, freezing the provider.
  • Verification not blocking, so failures accumulate unread.
  • Contracts as documentation rather than generated from usage.
  • Treated as a complete replacement for integration and end-to-end testing.

Interview question

"How does contract testing let two teams deploy independently, and what does it not tell you?"