|

Contract Testing With Pact: The Missing Test Layer Every Microservices Team Needs

Your unit tests pass. Your E2E tests pass. But your services cannot talk to each other in production. The missing layer: contract testing. Pact verifies that API contracts between services stay in sync — without deploying anything.

What Contract Testing Solves

In microservices, each team owns a service. Team A changes their API response format. Team B’s tests still pass because they mock Team A’s API. In production, Team B’s service crashes because the real response changed.

Contract testing catches this before deployment.

Consumer-Driven Contract Testing with Pact

// Consumer side: define what you expect from the provider
import { PactV3 } from '@pact-foundation/pact';

const provider = new PactV3({
  consumer: 'OrderService',
  provider: 'UserService',
});

test('get user by ID', async () => {
  provider
    .given('user with ID 1 exists')
    .uponReceiving('a request for user 1')
    .withRequest({ method: 'GET', path: '/api/users/1' })
    .willRespondWith({
      status: 200,
      body: {
        id: 1,
        name: like('John Doe'),
        email: like('john@example.com'),
      },
    });

  await provider.executeTest(async (mockserver) => {
    const response = await fetch(mockserver.url + '/api/users/1');
    const user = await response.json();
    expect(user.name).toBeDefined();
    expect(user.email).toContain('@');
  });
});

Where Contract Testing Fits

Test TypeWhat It ValidatesSpeed
UnitIndividual functionsMilliseconds
ContractAPI agreements between servicesSeconds
IntegrationServices working togetherMinutes
E2EFull user flowsMinutes

Contract tests run in seconds (no real services needed), catch integration bugs before deployment, and give teams confidence to deploy independently.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.