Bird
Raised Fist0
Microservicessystem_design~7 mins

Contract testing (Pact) in Microservices - System Design Guide

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
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.

Practice

(1/5)
1. What is the main purpose of contract testing in microservices using Pact?
easy
A. To check database schema consistency
B. To test the user interface of a microservice
C. To verify that services agree on request and response formats
D. To measure the performance of a microservice

Solution

  1. Step 1: Understand contract testing role

    Contract testing ensures that two services agree on how they communicate, specifically the request and response formats.
  2. Step 2: Identify Pact's function

    Pact automates contract testing by creating and verifying these agreements between microservices.
  3. Final Answer:

    To verify that services agree on request and response formats -> Option C
  4. Quick Check:

    Contract testing = Verify service agreements [OK]
Hint: Contract testing checks communication agreements, not UI or performance [OK]
Common Mistakes:
  • Confusing contract testing with UI testing
  • Thinking contract testing checks database schemas
  • Assuming contract testing measures performance
2. Which of the following is the correct Pact file format used to define a contract?
easy
A. JSON
B. YAML
C. XML
D. CSV

Solution

  1. Step 1: Identify Pact contract format

    Pact contracts are written in JSON format to describe interactions between services.
  2. Step 2: Eliminate other formats

    YAML, XML, and CSV are not used by Pact for contract files.
  3. Final Answer:

    JSON -> Option A
  4. Quick Check:

    Pact contract format = JSON [OK]
Hint: Pact contracts are JSON files describing service interactions [OK]
Common Mistakes:
  • Assuming Pact uses YAML or XML
  • Confusing data formats with contract formats
  • Thinking CSV can describe complex contracts
3. Given the following Pact interaction snippet, what is the expected response status code?
{"request": {"method": "GET", "path": "/users/123"}, "response": {"status": 200, "body": {"id": 123, "name": "Alice"}}}
medium
A. 404
B. 200
C. 500
D. 302

Solution

  1. Step 1: Read the response status in the Pact snippet

    The response object shows "status": 200, indicating a successful request.
  2. Step 2: Confirm status meaning

    Status 200 means OK, so the expected response code is 200.
  3. Final Answer:

    200 -> Option B
  4. Quick Check:

    Response status in Pact = 200 [OK]
Hint: Look for "status" field in response to find expected code [OK]
Common Mistakes:
  • Confusing request method with response status
  • Ignoring the status field in the response
  • Choosing common error codes instead of actual status
4. A Pact test fails because the provider service returns an extra field not defined in the contract. What is the best way to fix this?
medium
A. Remove the extra field from the provider service response
B. Ignore the extra field in the provider service
C. Disable contract testing for this interaction
D. Update the contract to include the extra field

Solution

  1. Step 1: Understand contract strictness

    Pact expects the provider response to match the contract exactly, including fields.
  2. Step 2: Adjust contract or provider

    If the provider adds a new field, the contract must be updated to reflect this change to keep tests valid.
  3. Final Answer:

    Update the contract to include the extra field -> Option D
  4. Quick Check:

    Provider adds field -> update contract [OK]
Hint: Keep contract and provider response in sync to pass tests [OK]
Common Mistakes:
  • Ignoring extra fields without updating contract
  • Removing fields from provider causing data loss
  • Disabling tests instead of fixing contract
5. You want to implement contract testing with Pact in a microservices system where multiple teams develop services independently. Which approach best ensures smooth integration?
hard
A. Each team publishes their Pact contracts to a shared broker for others to verify
B. Teams test contracts only locally without sharing
C. Use end-to-end tests only, skipping contract tests
D. Manually review API changes without automated tests

Solution

  1. Step 1: Identify best practice for contract sharing

    Using a shared Pact broker allows teams to publish and verify contracts centrally, enabling independent development with integration confidence.
  2. Step 2: Compare alternatives

    Local-only tests lack visibility; end-to-end tests are slower and less focused; manual reviews are error-prone.
  3. Final Answer:

    Each team publishes their Pact contracts to a shared broker for others to verify -> Option A
  4. Quick Check:

    Shared Pact broker = smooth integration [OK]
Hint: Use shared Pact broker for contract visibility and verification [OK]
Common Mistakes:
  • Skipping contract tests for only end-to-end tests
  • Not sharing contracts causing integration surprises
  • Relying on manual API reviews