Contract Testing with Fake Data: Pact and OpenAPI Mocking Explained

July 7, 2026

Regular API mocking has a blind spot: your frontend tests pass against a mock you wrote yourself, but nothing verifies that mock actually matches what the real backend returns. Contract testing closes that gap — it checks that both sides of an API integration agree on the same shape, using the fake data itself as the enforceable contract.


Why Mocking Alone Isn't Enough

If your frontend mocks `GET /orders/:id` returning `{ id, total, status }`, but the backend team renames `status` to `orderStatus` next sprint, your mocked tests keep passing — they're testing against your assumption, not reality. Contract testing catches that drift before it reaches production.


Approach 1: Pact (Consumer-Driven Contracts)

Pact works by having the frontend ("consumer") define what it expects from an endpoint using fake data, generating a "pact file" from that expectation, then replaying those exact requests against the real backend ("provider") in a separate verification step.

// consumer test
import { PactV3, MatchersV3 } from '@pact-foundation/pact'
const { like } = MatchersV3

provider.addInteraction({
  states: [{ description: 'an order with id 101 exists' }],
  uponReceiving: 'a request for order 101',
  withRequest: { method: 'GET', path: '/orders/101' },
  willRespondWith: {
    status: 200,
    body: like({ id: 101, total: 42.5, status: 'shipped' }),
  },
})

The like() matcher generated from your fake data tells Pact "match the type and shape, not the exact value" — so the contract stays valid even as the actual numbers change between runs.

On the backend side, the provider team runs a verification step that replays the exact same request against the real API and checks the response matches the contract. If someone renames a field, this step fails immediately — in CI, before either team ships.


Approach 2: OpenAPI-Driven Mocking (Prism)

If your team already maintains an OpenAPI spec, a lighter-weight alternative is generating a mock server directly from that spec using a tool like Prism. Because the mock is generated from the same contract the real API is supposed to implement, any drift between the spec and the real implementation is a documentation problem you can catch by validating both against the same spec — rather than a full separate contract-testing pipeline.

npx @stoplight/prism mock openapi.yaml
# serves realistic example responses based on your schema's examples

Prism uses the example fields inside your OpenAPI spec to generate responses — which means the quality of your mock depends entirely on how realistic those examples are. This is where generating good example values up front, with a tool like Dummy JSON Generator, pays off — vague placeholder examples like "string" produce useless mocks, while realistic examples produce a mock server that's actually usable for frontend development.


Pact vs OpenAPI Mocking: Which to Use

SituationRecommended Approach
Frontend and backend are separate teams/reposPact — enforces the contract across repo boundaries in CI
You already maintain an OpenAPI specPrism — reuses the spec you already have
Small team, one repo, moving fastPlain MSW mocking is usually enough — Pact's overhead isn't worth it yet
Multiple frontend clients consuming the same backendPact — one contract, verified against every consumer

The Bottom Line

Contract testing is worth the setup cost once more than one team owns different sides of an API boundary — the fake data you'd already be generating for mocks becomes the enforceable contract instead of just a local convenience. For a single small team, plain mocking is usually sufficient; Pact and OpenAPI-driven mocking earn their keep as the number of consumers and teams grows.