← Concepts

阅读中文版本

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.

testing

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

https://docs.pact.io/

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.