0
0
Microservicessystem_design~7 mins

Contract testing (Pact) in Microservices - System Design Guide

Choose your learning style9 modes available
Problem Statement
When multiple microservices evolve independently, integration failures occur because one service changes its API without notifying others. This leads to runtime errors, broken features, and delayed releases due to manual end-to-end testing.
Solution
Contract testing ensures that each service publishes a precise agreement (contract) of its API expectations. Consumers test against this contract to verify the provider meets those expectations before deployment, preventing integration issues early without full system tests.
Architecture
Consumer
Service
Contract
Provider CI
Provider CI

This diagram shows the consumer service generating tests against a contract stored in a repository. The provider service verifies this contract during its continuous integration to ensure compatibility.

Trade-offs
✓ Pros
Detects integration issues early in development, reducing costly runtime failures.
Enables independent deployment of microservices with confidence in API compatibility.
Reduces reliance on slow, brittle end-to-end tests by focusing on API contracts.
Improves collaboration by making API expectations explicit and versioned.
✗ Cons
Requires discipline to maintain and update contracts as APIs evolve.
Adds complexity to the development workflow with contract publishing and verification steps.
May not catch issues outside the API contract, such as data format or performance problems.
Use when multiple teams develop microservices independently with frequent API changes and when fast, reliable integration feedback is needed at scale (hundreds of services or more).
Avoid when the system is small with few services or when APIs are stable and rarely change, as the overhead may outweigh benefits.
Real World Examples
Netflix
Netflix uses contract testing to ensure their streaming microservices communicate reliably despite rapid independent deployments, preventing user-facing errors.
Spotify
Spotify applies Pact contract testing to coordinate between frontend and backend teams, enabling faster feature releases without integration regressions.
ThoughtWorks
ThoughtWorks popularized Pact to help clients reduce integration bugs in microservices by automating contract verification in CI pipelines.
Code Example
The before code calls the provider API directly without guarantees the provider supports the expected response. The after code uses Pact to define a contract with expected requests and responses, tests the consumer against a mock provider, and enables the provider to verify the contract in CI, preventing integration errors.
Microservices
### Before: No contract testing, direct API call without verification
import requests

def get_user_profile(user_id):
    response = requests.get(f"http://provider/api/users/{user_id}")
    return response.json()


### After: Consumer publishes Pact contract and verifies provider
from pact import Consumer, Provider

pact = Consumer('ConsumerService').has_pact_with(Provider('ProviderService'))

with pact:
    expected = {'id': 1, 'name': 'Alice'}
    pact.given('User 1 exists').upon_receiving('a request for user 1').with_request(
        'get', '/api/users/1').will_respond_with(200, body=expected)

    # Consumer test against mock provider
    result = get_user_profile(1)
    assert result == expected

# Provider CI runs pact.verify() to confirm contract compliance
OutputSuccess
Alternatives
End-to-End Testing
Tests the entire system flow including UI and multiple services together, rather than isolated API contracts.
Use when: Use when you need to validate full user journeys or complex workflows that span many services.
API Schema Validation
Validates API requests and responses against a static schema without verifying consumer-provider agreement.
Use when: Use when you want to enforce API format consistency but do not need consumer-driven contract guarantees.
Consumer-Driven Contract Testing (non-Pact)
Similar to Pact but may use different tools or protocols for contract definition and verification.
Use when: Choose based on team preferences, language support, or integration with existing toolchains.
Summary
Contract testing prevents integration failures by verifying API agreements between microservices early.
It enables independent deployments by making API expectations explicit and verifiable in CI pipelines.
Contract testing complements other testing types and is best for systems with many evolving services.