Examples¶
This directory contains examples demonstrating how to use Pact in Python for various testing scenarios. While this document and the documentation within the examples themselves are intended to be mostly self-contained, it is highly recommended that you read the Pact Documentation as well.
Each example is self-contained with its own dependency management using a pyproject.toml
file. This allows you to run examples independently without affecting your global Python environment or other examples.
The code within the examples is intended to be well-documented and you are encouraged to look through the code as well (or submit a PR if anything is unclear!).
Available Examples¶
HTTP Examples¶
aiohttp and Flask¶
- Location:
examples/http/aiohttp_and_flask/
- Consumer: aiohttp-based HTTP client
- Provider: Flask-based HTTP server
requests and FastAPI¶
- Location:
examples/http/requests_and_fastapi/
- Consumer: requests-based HTTP client
- Provider: FastAPI-based HTTP server
Message Examples¶
- Location:
examples/message/
- Status: 🚧 To be updated
Plugin Examples¶
- Location:
examples/plugins/
- Status: 🚧 To be updated
Running Examples¶
Each example can be run independently. Navigate to the specific example directory and use your preferred dependency manager.
Overview¶
Pact is a contract testing tool. Contract testing is a way to ensure that services (such as an API provider and a client) can communicate with each other. An interaction between a consumer (i.e., a HTTP client, mobile app, website, microservice, etc.) and a provider (i.e., a web server, microservice, etc.) would typically look like this:
sequenceDiagram
participant Consumer
participant Provider
Consumer ->> Provider: GET /users/123
Provider ->> Consumer: 200 OK
Consumer ->> Provider: GET /users/999
Provider ->> Consumer: 404 Not Found
Pact allows for each side of the interaction to be tested independently. Pact achieves this by mocking the other side of the interaction:
sequenceDiagram
box Consumer Side
participant Consumer
participant P1 as Pact
end
box Provider Side
participant P2 as Pact
participant Provider
end
Consumer->>P1: GET /users/123
P1->>Consumer: 200 OK
Consumer->>P1: GET /users/999
P1->>Consumer: 404 Not Found
P1--)P2: Pact Broker
P2->>Provider: GET /users/123
Provider->>P2: 200 OK
P2->>Provider: GET /users/999
Provider->>P2: 404 Not Found
Pact is consumer driven. This means that the consumer is responsible for defining the interactions it expects from the provider through the pattern of
Given {provider state}
Upon receiving {description}
With {request}
Will respond with {response}
When the consumer tests are executed, a Pact mock server is set up that will respond to the requests as defined by the consumer. When the consumer tests are merged into the main branch, the Pact contract is sent to the Pact Broker.
When the provider tests are executed, all contracts are retrieved from the Pact Broker. The provider then sets up a mock client that will make the requests as defined by the consumer. Pact then verifies that the responses from the provider match the expected responses defined by the consumer.
In this way, Pact is consumer-driven and can ensure that the provider is compatible with the consumer. While the examples showcase both sides in Python, this is absolutely not required. The provider could be written in any language, and satisfy contracts from a number of consumers all written in different languages.
Consumer¶
Consumer tests define the contract by specifying the interactions the consumer expects from the provider. These tests focus on the consumer's perspective and needs.
Principles¶
- Core interactions are defined: Only test the interactions your consumer actually uses
- Minimal requests and responses: Define only the required headers, query parameters, and body fields that your consumer needs
- Consumer-driven: The consumer decides what it needs from the provider, not what the provider offers
- Independent testing: Consumer tests run against a Pact mock provider, not the real provider
Best Practices¶
- If your consumer doesn't use a field from the provider's response, it should be safe for the provider to remove that field
- Use Pact matchers to make contracts flexible (e.g.,
match.integer
instead of hardcoded values) - Test error scenarios your consumer needs to handle (4xx, 5xx responses)
- Keep contracts focused on business logic, not implementation details
Contract Publishing¶
When consumer tests pass, the generated Pact contracts should be published to a Pact Broker. This makes them available for provider verification and enables the consumer-driven workflow.
Provider¶
Provider tests verify that the actual provider implementation satisfies all contracts defined by its consumers. These tests ensure the provider can fulfill its obligations in the consumer-provider relationship.
Core Principles¶
- Verify all consumer contracts: The provider must satisfy every interaction defined by all its consumers
- Provider state management: Set up the correct application state before each interaction is verified
- Real provider testing: Verification runs against the actual provider implementation, not mocks
- Fail fast: Any contract violation should cause provider tests to fail immediately
Provider States¶
Provider states are a key concept for ensuring your provider is in the correct state before an interaction:
- Setup: Use provider state callbacks to configure your application (e.g., create test data)
- Isolation: Each interaction should have a clean, predictable state
- Mocking: Mock external dependencies (databases, APIs) rather than requiring real infrastructure
Contract Retrieval¶
Provider tests retrieve contracts from the Pact Broker and verify them against the running provider:
- Use selectors to choose which contracts to verify (e.g., latest, main branch, specific versions)
- Configure which consumer versions to verify based on your deployment strategy
- Publish verification results back to the broker
Broker¶
The Pact Broker acts as the central contract repository and coordination point between consumers and providers. It stores contracts, verification results, and provides tools for managing the contract testing workflow.
How It Works¶
- Contract storage: Consumers publish their contracts to the broker after successful test runs
- Contract retrieval: Providers fetch relevant contracts from the broker for verification
- Verification results: Providers publish verification results back to the broker
- Visibility: Teams can see which contracts exist, their verification status, and compatibility matrix
Publishing Contracts¶
Consumers should publish contracts when:
- Consumer tests pass successfully
- Changes are merged to main branch
- Deploying to production environments
Retrieving Contracts¶
Providers can use selectors to determine which contracts to verify:
- Latest: Most recent contract from each consumer
- Branch-based: Contracts from specific git branches (e.g.,
main
,develop
) - Environment-based: Contracts from consumers deployed to specific environments
- Tag-based: Contracts tagged with specific labels
Versioning Strategy¶
- Use semantic versioning or commit SHA for contract versions
- Tag contracts when deploying to different environments
- Use "can-i-deploy" checks before releasing to ensure compatibility