Skip to content

Contract Testing

Given this caller sends X, the service returns Y. Derived from the API contract — and the layer that catches adr-drift before it becomes a CS ticket.

Owners: Developer Phase it lives in: How We Build (Volume IV) The corpus principle this enacts: The pipeline catches a different chain level at each stage.

Where it lives in the chain

How to do this

  • Practice — the contract file (OpenAPI / GraphQL schema / Avro) is the source. Tests are generated or derived from it; they don't restate it.
  • Practice — both sides run the contract. The provider's CI verifies "my implementation returns what the contract promises." The consumer's CI verifies "my expectations match the contract."
  • Practice — when the contract changes, the test breaks before the implementation does. The PR that changes the contract is the one that updates both consumers and providers.

What good practice looks like

Two services agree on a contract: POST /exams/:id/grade returns { gradedAt: ISO8601, balance: number }. The provider's contract test sends a sample request and asserts the response shape. The consumer's contract test mocks the response from the contract and asserts the consumer code accepts it. When the provider silently renames gradedAt to graded_at, the provider's contract test fails the build — not three days later when the frontend can't find the timestamp.

The wallet bug never reached production. The JWT outage did — because the gateway change had no contract test for token-claim compatibility. Contract testing is the layer that closes the gap between "my code works" and "my code works for the systems that depend on it."

200apps · How We Work · NWIRE