NOTE: This is a very short and super high-level example of how one might implement consumer-driven contract testing with Pact. It's meant to convey the principles and make it seem less daunting to start implementing. This continues from where I left off in my first article.
Consumer-Driven Contract Testing with Pact: A Recap
Consumer-Driven Contract Testing (CDCT) is a testing approach that ensures compatibility between services by having the consumer define the expectations for how it interacts with the provider. Pact is a popular tool for implementing CDCT, allowing you to verify that both consumer and provider are aligned in their interactions.
In CDCT, the consumer application defines contracts that specify the requests it expects the provider to fulfill. These contracts are then shared with the provider, which runs verification tests to confirm it can meet the consumer's expectations. This process fosters clear and efficient communication between teams, ensuring that changes in one service don’t break another.
Why Pact?
See the first article in the series.
Key Concepts in Pact
- Consumer: The application that sends requests and expects responses.
- Provider: The service that fulfills requests made by the consumer.
- Pact Contract: The agreement, defined by the consumer, specifying expected request-response pairs.
- Verification: The provider validates the contract, ensuring it meets consumer expectations.
- Pact Broker: An optional service that stores and shares contracts, making collaboration easier.
Getting Started: Code Example
Let's implement CDCT with a simple Node.js example using Pact. First, set up your project and install Pact dependencies:
npm init -y
npm install @pact-foundation/pact @pact-foundation/pact-node jest
Step 1: Define the Contract in the Consumer
Create a test file, consumer.test.js, where the consumer’s expectations are specified.
const { Pact } = require('@pact-foundation/pact');
const provider = new Pact({
consumer: 'ConsumerApp',
provider: 'ProviderService',
port: 1234
});
describe('Pact with ProviderService', () => {
beforeAll(() => provider.setup());
afterAll(() => provider.finalize());
test('should receive a valid response for a specific request', async () => {
// Define consumer expectations here
await provider.addInteraction({
state: 'provider has valid data',
uponReceiving: 'a request for information',
withRequest: { method: 'GET', path: '/data' },
willRespondWith: { status: 200, body: { id: 1, name: 'Test Data' } }
});
// Trigger the request and assert results
const response = await fetch('http://localhost:1234/data');
const data = await response.json();
expect(data).toEqual({ id: 1, name: 'Test Data' });
await provider.verify();
});
});
In this test, the consumer defines an expectation: when it sends a GET request to /data, it expects a 200 response with specific data.
Step 2: Publish the Contract
If you’re using a Pact Broker, you can publish the generated contract to share it with the provider.
npx pact publish ./pacts --consumer-app-version 1.0.0
Step 3: Provider Verification
On the provider side, create tests that use the contract to verify compatibility. Here’s a simplified provider verification setup:
const { Verifier } = require('@pact-foundation/pact');
describe('Provider Verification', () => {
test('validates contract with ConsumerApp', async () => {
const opts = {
providerBaseUrl: 'http://localhost:8080',
// ...
};
await new Verifier(opts).verifyProvider();
});
});
This test verifies the provider against the consumer’s expectations, ensuring compatibility.
Conclusion
By using Pact, you can implement Consumer-Driven Contract Testing effectively, ensuring your services evolve in harmony. CDCT enables quick feedback on contract compliance, reduces integration errors, and fosters collaborative development between service teams.
Top comments (0)