Contract Testing
Contract testing verifies that a consumer and provider agree on request and response shapes, catching integration breakage without running a full end-to-end environment.
Definition
Contract testing captures the expectations a consumer has of a provider and verifies the provider against them, or vice versa. The contract is a versioned artifact, often generated from consumer tests or an OpenAPI document. Provider verification runs in the provider's pipeline, so a breaking change is caught before deployment without standing up every dependent service.
Context and scope
Contract testing is used in microservices, frontend/backend boundaries, and third-party integrations where full end-to-end environments are slow, flaky, or unavailable.
Common misconceptions
- Contract testing replaces end-to-end tests — it verifies interfaces, not business workflows or real infrastructure
- A schema match proves compatibility — semantic meaning, optionality, and error behavior also matter
- The provider can change freely if it updates the contract — consumers must publish and verify their expectations
Anti-patterns
- Testing only the happy-path response and ignoring error shapes
- Letting the provider generate a contract from its implementation without consumer input
- Treating a passing contract test as proof that the integration works in production
Related concepts
Related examples
Authoritative source
Test the boundary, not the world
An end-to-end test that boots five services is slow and fails for unrelated reasons. Contract testing isolates the boundary: the consumer records what it needs, and the provider verifies it can satisfy those expectations. The result is a fast, focused check that runs in both pipelines.
{
"consumer": "web-checkout",
"provider": "orders-api",
"interaction": "get order",
"request": { "method": "GET", "path": "/orders/42" },
"response": {
"status": 200,
"body": { "id": "42", "status": "paid", "total": 4200 }
}
}
The example is a Pact-style contract. The details vary by tool; the key is that expectations are versioned and verified by the provider.
Cover errors and optionality
A contract that only checks a successful response misses the shapes clients depend on when things fail. Include not-found, validation error, and authorization responses. Mark fields optional or required deliberately; a field that becomes nullable can break a consumer that assumes a string. Contract tests should also assert content types and status codes, not only the body.
Keep it honest
A provider can pass contract tests and still break in production if infrastructure, timeouts, or data differ. Use contract tests for interface compatibility and keep a smaller number of end-to-end tests for critical flows. Publish contracts from consumer pipelines, verify them in the provider pipeline, and block deployment on a failed verification. A contract nobody verifies is documentation.
When to use it
Use contract testing when many consumers depend on a service and full integration environments are expensive. The advantage is fast, targeted feedback and explicit interfaces; the drawback is contract maintenance and coverage gaps around real infrastructure. Compared to end-to-end testing, it catches interface drift earlier but does not prove the whole system works.