Test Automation

Contract Testing with Pact: A QA Guide for Microservices and API-First Teams

Integration tests are slow, brittle, and often lie. Contract testing with Pact solves the problem that no amount of end-to-end testing can: verifying that two services actually agree on their shared interface — before they ever talk to each other in production.

K
KiwiQA Automation Practice
KiwiQA Engineering
5 May 2026
8 min read
Test AutomationAPI TestingMicroservicesContract TestingPact

Every microservices architecture eventually develops the same testing problem: you have twenty services, each with their own test suite, and yet production still breaks whenever two services are updated independently. Your unit tests pass. Your integration tests pass. And then something that used to work silently stops working because a team changed the shape of a JSON field and nobody noticed. Contract testing exists to close this gap — and Pact is the most widely adopted framework for doing it.

The core insight behind contract testing is simple. In a microservices system, the real risk isn't whether each service works in isolation — it's whether services agree on how they communicate. A consumer service expects a field called customerId; the provider renames it to customer_id. Both services pass all their own tests. The integration test environment may never cover this exact combination. But in production, the consumer breaks silently. Contract testing makes this agreement explicit, verifiable, and automated.

What Pact Actually Does

Pact is a consumer-driven contract testing framework available for most major languages including JavaScript, Java, Python, Go, Ruby, .NET and more. The workflow has three steps. First, the consumer team writes a test that defines what it expects from the provider — a specific request, a specific response shape. Pact captures this expectation as a contract file (a .json pact). Second, the consumer's test suite runs against a Pact mock server, verifying the consumer correctly handles the response it expects. Third, the provider team runs the contract against their actual service to verify they can satisfy every expectation the consumer has declared.

The crucial structural property is that the contract is generated by the consumer, not negotiated between teams. The consumer states what it actually uses from the provider's API — not what the API documentation says, not what the full response looks like, but specifically the fields and behaviour the consumer depends on. This means providers are only tested against real consumer requirements, and consumers are only bound by what they actually use.

Contract testing doesn't replace integration testing — it makes integration testing unnecessary for the specific concern of interface compatibility. Each team stays fast, each deployment stays independent, and the compatibility check happens in CI before code ever reaches a shared environment.

Pact Broker: Sharing Contracts Across Teams

In any multi-team organisation, contract files need to be shared between the consumer team (who generates them) and the provider team (who must verify against them). PactFlow — the hosted Pact Broker — solves this coordination problem. Consumer teams publish contracts to PactFlow after each build. Provider teams pull the latest contracts and verify against them as part of their CI pipeline. PactFlow maintains a full version history of contracts, provides a network graph of which services depend on which, and most importantly powers the can-i-deploy check.

The can-i-deploy CLI tool is where contract testing delivers its most concrete value. Before any service deploys to any environment, it queries PactFlow: has this version of the consumer been verified against this version of the provider? If the compatibility check hasn't passed, deployment is blocked — automatically, in CI, without requiring a human to coordinate between teams. This is the mechanism that makes independent deployment safe in a microservices system.

Setting Up Pact in a JavaScript/TypeScript Stack

For teams using Node.js or TypeScript, the setup involves three packages: @pact-foundation/pact for consumer-side contract generation, @pact-foundation/pact for provider-side verification, and the Pact CLI for the can-i-deploy check. Consumer tests use a PactV3 or PactV4 instance to define interactions — the expected request and the mock response — and then verify the consumer correctly processes that response. The resulting pact file is published to PactFlow via the Pact CLI in the CI step after tests pass.

Common Pitfall: Consumer tests that verify the entire response structure — including fields the consumer never actually uses — create brittle contracts that block valid provider changes. Write consumer tests that only assert on fields the consumer code actually reads. This is the discipline that makes contract testing genuinely useful rather than just another layer of coupling.

Provider Verification in CI

Provider verification runs the real provider service (not a mock) against every consumer contract it must satisfy. The Pact framework replays each consumer interaction — sending the defined request to the running provider and verifying the response matches the consumer's expectations. Provider verification should run in CI on every provider build, and the result should be published back to PactFlow so that can-i-deploy queries have accurate data. Provider teams should treat a failed verification the same way they treat a failing unit test: the build does not ship until the contract is satisfied or the consumer is consulted and the contract is updated.

Where Contract Testing Fits in Your Overall Strategy

Contract testing is not a replacement for all integration testing — it is a replacement for the subset of integration testing that validates interface compatibility between services. End-to-end tests still have a role for validating business workflows that cross multiple services. But those tests become dramatically more stable when you know each service boundary is already contract-verified. The standard recommendation is to use the testing pyramid with contract tests occupying the layer between unit tests and full integration tests: fast, isolated, but covering the real compatibility concern that unit tests miss.

KiwiQA's automation practice implements contract testing as part of API-first and microservices QA strategies for clients across fintech, healthtech and SaaS verticals. If your team is experiencing the classic symptom — integration tests that pass while production breaks on API mismatches — contract testing with Pact is the most direct structural fix. KiwiQA's test automation practice can assess your current API test coverage and build a Pact implementation plan tailored to your stack.

Frequently Asked Questions

Enjoyed this? Explore more below.
In this article
What Pact Actually Does
Pact Broker: Sharing Contracts Across Teams
Setting Up Pact in a JavaScript/TypeScript Stack
Provider Verification in CI
Where Contract Testing Fits in Your Overall Strategy
Share
Share on LinkedIn
Contract Testing with Pact: A QA Guide for Microservices and API-First Teams | KiwiQA Blog | KiwiQA