Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Consumer-Driven Contract Testing

Pattern

A reusable solution you can apply to your work.

“The suppliers of a service … should do no more than what is expected of them by their consumers.” — Ian Robinson

Let each consumer of an API declare the parts of the contract it actually depends on, then verify the provider against every consumer’s declaration before release, so changes that break a real caller never reach production.

Also known as: CDCT, Consumer-Driven Contracts, Pact testing.

Understand This First

  • Contract – the agreement between caller and provider that this pattern makes executable.
  • Interface – what the contract describes; the specific shape a consumer depends on.
  • Consumer – the party that depends on the interface and drives what the contract must cover.
  • API – the most common kind of interface this pattern is applied to.

Context

Most non-trivial systems are split into pieces that talk to each other: a web app and its backend, a backend and its database, a product service and a payments service, a coding agent and the MCP server it calls. Each boundary carries a contract. If the provider changes the shape of a response, renames a field, or tightens a validation rule, every caller that relied on the old shape may break the next time it runs.

The classic way to catch these breakages is an end-to-end test: spin up both sides, send real requests, watch the result. End-to-end tests are slow, flaky, and environment-hungry. Teams skip them or let them rot. Provider teams ship a change on green unit tests, consumers find out at 2 a.m., and everyone agrees this should never happen again until it does.

The problem has sharpened in 2026 because agents now write much of the code on both sides. An agent asked to “simplify the response payload” will happily drop a field that a downstream agent reads every minute. Without an explicit, machine-checkable contract between the two, the break is invisible until production.

Problem

Two services need to stay compatible across independent release cycles. Testing them together is too expensive to run on every change. Testing them alone with mocks is cheap but lies: the mocks can drift from the real provider, and the provider has no way to know which parts of its surface any consumer actually relies on. How do you get fast, deterministic verification that each side still honors the agreement, without paying the cost of a full integration environment?

Forces

  • End-to-end environments are expensive to build and brittle to run; you cannot gate every pull request on them.
  • Provider unit tests check what the provider thinks its contract is, which is rarely the same as what any consumer actually depends on.
  • Consumer tests that use hand-rolled mocks drift from reality because nothing forces the mock to match the real provider.
  • Providers can’t keep every historical field forever; they need to know which parts of their surface are safe to change.
  • Consumers cannot wait for the provider team to schedule coordinated releases; they need to move at their own pace.
  • When agents generate code on either side, unwritten assumptions break silently and fast.

Solution

Let the consumer write the test, and let the contract fall out of that test as a machine-readable artifact the provider verifies against. The workflow has three moving parts: a consumer test, a contract file, and a provider verification step.

The consumer writes a test against a local stub. The test describes a specific interaction: “given this request, I expect a response with these fields and these types and these values.” The test framework records that interaction as a JSON file called a pact or contract. Pact is the canonical implementation; Spring Cloud Contract and several smaller tools fill the same role on other stacks. The consumer test runs entirely locally against the stub and passes or fails on its own CI.

The contract file becomes the shared artifact. It names the provider, the consumer, and the set of interactions the consumer depends on. It is small, versioned, and deterministic. Teams store contracts in a broker (Pactflow, an OSS Pact Broker, or any artifact registry) so provider and consumer can reference the same file without pointing at each other’s source trees.

The provider replays every contract against its real implementation. On the provider’s CI, a test harness loads each consumer’s contract, spins the provider up, sends the recorded requests, and checks the real responses against the recorded expectations. If the provider changed something a consumer depends on, the provider’s build fails. If the change touched nothing any consumer cares about, every build stays green.

The pattern works because it inverts the usual direction of authority. The provider no longer guesses which fields “matter.” The consumers tell the provider, in code that runs, which fields matter to them. Anything outside that set is the provider’s to change freely.

How It Plays Out

A retail team owns an orders service. Three other services consume it: a shipping service that reads order.items[], a billing service that reads order.total_cents, and a customer dashboard that reads almost everything. Each consumer writes a Pact test describing the exact fields it uses and publishes the resulting contract to a broker. When the orders team wants to rename the total_cents field, they run the provider-side verification before merging. Shipping and the dashboard pass (neither reads the field). Billing fails immediately. The provider team applies a Parallel Change: they add amount_cents alongside total_cents, ship it, work with billing to migrate, then finally remove total_cents once the contract no longer mentions it. No service ever saw a broken response.

A platform team is rolling out an agent-facing MCP server that exposes ten tools. Each tool has a response schema. Internal agent teams wrap the tools in thin clients and write CDCT-style tests that describe the specific tool calls and fields they depend on. When the platform team’s on-call engineer asks an agent to “trim the response of the search_documents tool,” the agent does so, runs the full contract verification suite, and sees three consumer contracts turn red. The agent reports the collisions instead of shipping. The platform team renames the change to an additive expand step, and the red tests go green.

Tip

When you direct an agent to modify an API, hand it the contract directory as a read-only input and tell it to run the verification suite after every structural change. Agents left to infer “backwards compatibility” from prose comments will miss fields that no comment ever mentioned. A machine-checkable contract collapses the ambiguity the agent otherwise has to guess through.

A startup with one provider and two consumers adopts CDCT without the full broker machinery. They commit contract files into the provider repository next to the code, and their CI runs the verification step on every pull request. It isn’t elegant, but it catches the regressions that used to leak to staging, and the whole thing cost a weekend to set up. The pattern scales from this minimal setup up to enterprise configurations with dozens of services and hundreds of contracts; the shape doesn’t change, only the plumbing does.

Consequences

Benefits. The provider gets a precise map of which parts of its surface real consumers depend on, and can change everything else without fear. The consumer gets fast, deterministic local tests that don’t need the provider running. End-to-end environments stop being the bottleneck for verifying compatibility, so teams stop skipping them out of frustration. When a change does break something, the failure happens on the provider’s CI before the change lands, not at 2 a.m. in production. For agentic teams, a contract file is a far more reliable specification than a paragraph of prose: an agent can read it, run it, and act on the result.

Liabilities. You pay for the discipline up front. Every consumer has to write and maintain contract tests, and every provider has to wire in the verification step. If consumers write contracts that mirror the full response rather than just the parts they use, the pattern inverts: the provider can’t change anything, because every field is “depended on.” Teams that fall into this trap usually discover that their consumer tests are doing snapshot testing by accident. Contracts also need governance: who decides when to bump a contract version, who owns the broker, how you retire contracts from consumers that no longer exist. Finally, CDCT verifies shape and values, not business correctness: two services can honor a contract perfectly and still be wrong about what the business wanted.

  • Depends on: Contract – CDCT makes an existing contract executable; without a contract concept there is nothing to test against.
  • Depends on: Interface – the interface is what the recorded pact describes.
  • Depends on: Consumer – the consumer is the party whose real usage drives the contract.
  • Refines: Test – CDCT is an integration-testing technique that narrows the scope of what a cross-service test has to cover.
  • Works with: Parallel Change – when a contract verification fails on the provider side, parallel change is the standard safe path to the new shape.
  • Works with: Deprecation – the lifecycle policy that decides when a contract may finally be retired.
  • Contrasts with: Test Pyramid – where the pyramid recommends a few slow end-to-end tests to cover cross-service flows, CDCT lets each side verify those flows alone against a shared artifact instead.
  • Complements: API – contracts are the most common way to keep a public or internal API safe to evolve.
  • Complements: Harness – the provider-side verification runs inside the standard test harness; no separate infrastructure is required.

Sources

Ian Robinson named and described Consumer-Driven Contracts in his 2006 Martin Fowler bliki essay, framing them as a service-evolution pattern: a provider should satisfy the intersection of its real consumers’ expectations, no more and no less. That piece is still the clearest statement of the core idea.

The Pact project, started by Beth Skurrie and collaborators around 2013, turned the pattern into a widely adopted toolchain. Pact’s design choices – consumer-driven test runner, JSON pact files, broker-hosted artifacts, provider-side verification – have shaped how most teams apply the pattern today. The Pact documentation is the most practical reference for day-to-day use.

Sam Newman’s Building Microservices (2015; second edition 2021) connected CDCT to the wider discipline of safe service evolution, including its interaction with deprecation policies and expand-contract-style interface changes across team boundaries.

The broader principle – that callers should drive what a provider promises, not the other way around – runs through the work of the Thoughtworks consultancy and the ThoughtWorks Technology Radar, which has recommended CDCT through multiple editions as a mature, low-regret practice.

Further Reading

  • Ian Robinson, “Consumer-Driven Contracts: A Service Evolution Pattern” (martinfowler.com, 2006) – the original essay; short, sharp, still the clearest framing.
  • The Pact documentation – the reference for the canonical open-source toolchain, including the broker, matching rules, and provider verification workflow.
  • Sam Newman, Building Microservices (O’Reilly, 2nd ed. 2021) – chapter on testing microservices; connects CDCT to deprecation, versioning, and team-level ownership.