Skip to content

Contract Testing

A contract test verifies that a consumer and a provider agree on their interface — the request/response shapes, status codes and events between two services — without deploying both together.

The consumer records its expectations as a contract (a pact). The provider runs that contract against its real implementation. If both pass, the integration is safe to ship.

Consumer test ──► pact file ──► Provider verification
(expectations) (JSON) (runs real provider)

This replaces fragile end-to-end environments with fast, independent checks — a natural fit for microservices and mobile/backend boundaries.

Use it for

  • Microservices and any consumer/provider split across teams
  • Mobile app against a backend API
  • Any interface where “we think we agree” is the risk

Avoid it when

  • There is one deployable, so a normal integration test is simpler
  • The API is trivial and stable and a schema test suffices
Tool Ecosystem Notes
Pact Multi (JS, Java, Go, .NET, Python, Ruby) The de-facto standard; broker for sharing
PactFlow Multi Hosted Pact broker + can-i-deploy
Spring Cloud Contract Java Producer and consumer verification
Schemathesis Multi Property-based testing from OpenAPI schemas
Dredd Multi Validate implementations against OpenAPI/API Blueprint
Postman / Newman Multi Contract assertions in collections
Terminal window
npm install -D @pact-foundation/pact
import { PactV3, MatchersV3 } from '@pact-foundation/pact';
const { like, integer } = MatchersV3;
const provider = new PactV3({ consumer: 'web', provider: 'users-api' });
it('gets a user by id', async () => {
provider
.given('user 42 exists')
.uponReceiving('a request for user 42')
.withRequest({ method: 'GET', path: '/users/42' })
.willRespondWith({
status: 200,
body: { id: integer(42), name: like('Ada') },
});
await provider.executeTest(async (mock) => {
const user = await getJson(`${mock.url}/users/42`);
expect(user.name).toBe('Ada');
});
});
  • One contract per consumer. Each consumer owns its own expectations.
  • Use matchers, not exact values. like('Ada') is not the point; the shape is.
  • Version the contract and share it via a broker. Then ask “can I deploy?” before release.
  • Do not contract-test internal functions — only the network boundary counts.
  • Gate deploys with can-i-deploy so a provider is only released if all consumer contracts still pass.

Self-assessment quiz

Pick one answer per question, then press Check answers.

  1. What does contract testing verify?
  2. Which tool is the de-facto standard for consumer-driven contracts?
  3. Why should a contract use matchers like `like("Ada")` instead of exact values?
  4. What does a Pact broker enable?