How to Do API Contract Testing: A Step-by-Step Method
A six-step method for API contract testing, from choosing where the contract lives to gating every release on it, with a contract suite built as a Test Run Pack in Shift-Left API.
This is lesson 5.6 of OpenAPI, Contract and Schema Testing. It pulls the earlier lessons together into one method; lesson 5.5 on schema validation is the most useful one to have read first. For the demo you need a trial edition, because Test Run Packs and CI aren't in the free edition.
How do you do API contract testing?
How to do API contract testing comes down to six steps: choose where the contract lives, make it precise, check every change to it, build a suite that checks the API conforms to it, run that suite as a gate in CI, and handle change deliberately. Most teams that "have contract tests" have done two or three of these. The value comes from doing all six, because a gap in any one lets a breaking change through.
What is API contract testing?
An API contract is the agreement between an API and its clients: which requests are accepted, and which responses come back, down to status codes, field names and types. API contract testing checks that both sides still keep it. The contract is written down, so the check doesn't depend on someone remembering how the API behaved last month.
Contract testing vs API testing vs unit testing
| Unit test | Contract test | Functional API test | |
|---|---|---|---|
| Question | Does this function work? | Does the interface still match the agreement? | Does the endpoint do the right thing? |
| Scope | One piece of code, dependencies faked | The boundary between API and clients | One endpoint or flow, real data |
| Example | The price formatter rounds to two decimals | price is still a number, name still present | Creating an order stores the right total |
| Breaks when | The code's logic changes | A field, type or status changes | The behaviour changes |
| Speed | Milliseconds | Seconds | Seconds to minutes |
The comparison that confuses teams is contract testing vs API testing. A contract suite can pass while the API computes the wrong total; a functional suite can pass while a field that a mobile app reads has been renamed. Each catches what the other misses.
Step 1: choose where the contract lives
There are two main approaches:
- Spec-first (provider-driven). The OpenAPI spec is the contract. The provider tests that it conforms; clients generate code and mocks from the spec. This suits public APIs and APIs with many clients you don't control.
- Consumer-driven. Each client writes down the requests it makes and the fields it reads, and the provider verifies every client's contract. Pact is the best-known tool; lesson 5.7 covers it.
Many organisations use spec-first for their public surface and consumer-driven contracts between internal services.
Step 2: make the contract precise
A contract can only enforce what it states. Before writing tests, tighten the spec:
- Mark response fields as
requiredwhere clients depend on them. - Use
enumfor fixed sets: statuses, roles, error codes. - Document every status the API really returns, including its 400s.
- Define one error envelope and use it everywhere.
The sandbox spec is a useful warning: its response schemas mark nothing as required, so a contract test can check types but not presence.
Step 3: check every change to the contract
Every pull request that touches the spec should be diffed against the last released version and each change classified as breaking or not. A new required request field, a removed endpoint, a narrowed enum or a changed type is breaking; a new optional field or endpoint isn't. This catches a break before any code runs.
Step 4: build a conformance suite
The provider-side suite checks that the running API matches the contract, operation by operation:
- Each documented success status, with a body that fits the response schema.
- Each documented error status, with the error envelope.
- Each request rule enforced: missing required fields, wrong types, values past their limits.
- Nothing undocumented: no status, and no field type, that the spec doesn't describe.
What the suite deliberately leaves out: business logic, performance and data correctness. Those belong to functional and performance suites.
Step 5: gate CI on it
Run the contract suite on every pull request to the provider and before every deploy. Fail the build below a pass rate you choose, and publish the results where both the provider and client teams can see them. A contract suite nobody runs is documentation.
Step 6: handle change deliberately
When the contract has to break, don't break it in place. Add a new version, keep the old one working for a stated period, tell clients, and keep testing both until the old one is retired. Lesson 5.8 covers versioning.
Common mistakes
- Treating the spec as documentation only. If nothing fails when the API and spec disagree, the spec will drift.
- Putting business rules in the contract suite. It becomes slow and flaky, and teams stop trusting it.
- Running it only on the provider. Clients should see the result, or at least be told about breaking changes.
- "Fixing" a failing contract test by editing it. First decide whether the API or the contract is wrong.
For the three common approaches and their tools, read API contract testing: what it is, how it works and tools.
In Shift-Left API: a contract suite as a Test Run Pack
In Shift-Left API the spec is the contract. Steps 3 to 5 map onto three features: change detection on re-import (step 3, walked through in lesson 9.3), tests generated from the spec (step 4), and Test Run Packs that a pipeline runs (step 5). Test Run Packs, schedules and CI come with Professional, Enterprise and the 15-day trial.
- Import
https://demo.totalshiftleft.ai/openapi/rest.jsonand open Products. Click Generate Tests for All: every Products endpoint gets tests for its documented statuses, its request rules and its response outline. - Click Execution in the top bar, then New Test Run Pack. Choose Functional, and name it Store API contract.
- On step two, pick the project and tick the Products tests. Finish the wizard; lesson 9.10 walks through all five steps.
- Click Run Now. The summary shows passed, failed and total. View results opens the run in Reporting, with the execution type Manual.
- To make it a gate, run the same pack from your pipeline with a minimum pass rate, using the ready-made GitHub Action, Azure DevOps task or Jenkins plugin. Lesson 9.15 shows the pipeline step and the pass-rate rule.
Approved spec changes create new endpoint versions; existing tests are never rewritten to match. When a contract test fails, you decide whether the API or the spec is wrong. The API contract testing page shows the rest of the workflow.
Try it yourself
With a trial, import the sandbox spec, generate tests for every Products endpoint, put them in a Test Run Pack in Execution, and click Run Now. Read the summary, then find the run in Reporting: what is its execution type?
Recap
- How to do API contract testing: choose the contract, make it precise, diff every change, build a conformance suite, gate CI on it, and version breaking changes.
- What is API contract testing? Checking that an API and its clients still agree on the interface, against a written contract.
- Contract testing vs API testing: one checks the interface, the other the behaviour, and contract testing vs unit testing is the boundary versus one piece of code. You need all three.
Next: lesson 5.7, what Pact contract testing is, the consumer-driven side of step 1.
Try it: With a trial, import https://demo.totalshiftleft.ai/openapi/rest.json, generate tests for every Products endpoint, put them in a Test Run Pack in Execution and click Run Now.
Frequently asked questions
What is API contract testing?+
It is testing that an API and the clients that call it still agree on the interface between them: the requests the API accepts and the responses it returns, down to status codes, fields and types. The agreement is written down, usually as an OpenAPI spec or as consumer contracts, and the tests check both sides against it.
What is the difference between contract testing vs API testing?+
An API test checks what an endpoint does: that creating an order stores it with the right total. A contract test checks only the interface: that the response still has the fields, types and statuses clients depend on. A contract suite can pass while the API computes the wrong total; a functional suite can pass while a field clients read has been renamed. You need both.
How does contract testing vs unit testing compare?+
A unit test checks one piece of code in isolation, usually with its dependencies faked, and runs in milliseconds inside the build. A contract test checks the boundary between two services over the network or against the agreed definition. Unit tests can't tell you that a serializer change renamed a field in the JSON; contract tests exist for exactly that.
Related lessons
Pact turns each consumer's expectations into a contract the provider must verify. See how it works on one interaction, where it beats spec-driven contracts, where it doesn't, and where Shift-Left API fits.
Schema validation in API testing happens in three places: requests, responses, and the spec itself as it changes. Find real drift between the sandbox store and its spec, then see how Shift-Left API catches both kinds.
Your spec is a contract, and it changes. Import a new version into Shift-Left API, see which changes break clients, approve them, and test the new version.
Read more on the blog
API contract testing verifies that providers and consumers honor a shared interface contract (an OpenAPI schema or a Pact consumer contract), so breaking changes are caught in the pull request and services can deploy independently. Examples, approaches, a CI workflow and tools.
Contract testing tools compared: Pact, PactFlow, Spring Cloud Contract, Specmatic, Schemathesis, Dredd, Prism, Microcks and OpenAPI diff tools, with a comparison table, open-source and Java picks, and how to choose.