How to Write a Contract Test with Mock in Python
Use unittest.mock to verify a consumer's expectations match the provider's response shape in a Python contract test.
Python code
30 linesfrom unittest.mock import Mock
# Contract test: verify consumer expects data shape that provider delivers.
# We mock the provider and assert the consumer's calls match the agreed contract.
def fetch_user(provider_client, user_id):
"""Consumer code: expects provider to return {'id', 'name', 'email'}."""
response = provider_client.get_user(user_id)
if not response or not all(k in response for k in ('id', 'name', 'email')):
raise ValueError(f"Provider contract violated for user {user_id}")
return response
def test_consumer_contract():
# Mock the provider with a valid contract-shaped response
mock_provider = Mock()
mock_provider.get_user.return_value = {
'id': 42,
'name': 'Alice',
'email': 'alice@example.com'
}
result = fetch_user(mock_provider, 42)
# Verify the consumer made exactly the expected call (contract on request)
mock_provider.get_user.assert_called_once_with(42)
assert result == {'id': 42, 'name': 'Alice', 'email': 'alice@example.com'}
print("Consumer contract test passed: provider response matches expectation.")
if __name__ == "__main__":
test_consumer_contract()
Output
Consumer contract test passed: provider response matches expectation.
How it works
The Mock class from unittest.mock simulates the provider, allowing you to test the consumer in isolation. By setting return_value on the mock, you define the contract shape the provider must deliver. The consumer code validates this shape and raises if fields are missing, ensuring contract compliance. assert_called_once_with verifies the consumer made the exact expected call, checking the request side of the contract. This pattern catches mismatches early without needing a live provider.
Common mistakes
- Forgetting to assert the mock was called with the correct arguments
- Not validating the response shape in the consumer code when testing the contract
- Using a real provider instead of a mock, making the test slow and flaky
Variations
- Use pytest with a fixture to create the mock provider and keep tests DRY
- Add a schema validation library like pydantic in the consumer to enforce the contract
Real-world use cases
- Verifying that a frontend service expects the same user fields an API returns before deployment.
- Testing a payment gateway client against a mocked provider to prevent integration failures in CI.
- Validating an internal microservice's API contract when the provider team changes response formats.
Sponsored
More from Testing & modern typing
- Capture stdout and stderr with pytest capsys easy
- Characterization Test for Legacy Python Code medium
- Dataclass with Type Hints Fields in Python easy
- Dependency Injection in Python for Testability easy
- Design Data Helpers with Python TypedDict and Literal easy
- Fix and Test a Regression Bug in Python with Unit Tests easy
Keep learning
Related tutorials and quizzes for this topic.