What Is Microservices Testing? Layers, Mocks and Contracts
Microservices testing checks each service alone, the contracts between services, and a few journeys across them. Here are the layers, a store split into three services, and how mocks and a contract pack fit.
This is lesson 6.8 of Test Data, Mocks and End-to-End API Testing, the last in the track. It pulls the track together: mocks from lesson 6.1, data from lessons 6.3 to 6.5, and the integration and journey tests from lessons 6.6 and 6.7.
What is microservices testing?
What is microservices testing? It's testing a system built from small services that deploy independently and talk over the network, and it has to answer three questions: does each service work on its own, do services still agree on how they talk to each other, and do the few journeys that cross many services still work end to end. The answer is layers, each one cheaper and more numerous than the one above it.
Why microservices change testing
In a single application, a refactor that breaks a caller fails the build. In microservices, the caller is in another repository, owned by another team, deployed on another day. Three things follow:
- The contract becomes the test boundary. Each service's API spec is a promise to every consumer. Breaking it is the most common way to break production.
- The network is part of the system. Latency, timeouts, retries and partial failures are normal, not exceptional.
- Full-system environments are expensive. Twenty services, each with its own data, rarely line up in one staging environment. Tests that need all of them are slow and flaky.
The layers of microservices testing
| Layer | What it tests | Dependencies | How many | When it runs |
|---|---|---|---|---|
| Unit | Code inside one service | None, or in-process doubles | Thousands | Every commit |
| Component | One service through its API | Its database real; other services mocked | Hundreds | Every merge |
| Contract | That a service still matches the spec consumers rely on | The real service, one at a time | One set per API | Every merge, both sides |
| Integration | Two or more real services or stores together | Real | Tens | Every merge or deploy |
| End-to-end | A business journey across many services | All real | A handful | After deploy, on a schedule |
The shape matters more than the exact numbers: lots of fast, isolated tests at the bottom, very few slow, connected ones at the top.
A microservices testing example
Imagine the sandbox store split into three services:
- users-service owns
/api/v1/users. - catalog-service owns
/api/v1/products. - orders-service owns
/api/v1/orders, and calls the other two to expand an order'suserandproduct.
Here's how each layer applies to the orders-service:
- Unit: the code that builds an order response from three lookups, with the lookups stubbed in-process.
- Component: start orders-service with its own database, and point its users and catalog URLs at mock servers generated from those services' specs. Test
POST /orders,GET /orders/{id}?expand=user,product, and what happens when the catalog mock answers 503 or takes two seconds. - Contract: on catalog-service's side, check on every merge that its real responses still match the spec the orders team generated their mock from: same fields, same types, same status codes. If catalog renames
price, this fails in catalog's build, not in orders' production. - Integration: with real users and orders services, delete a user and check the order still reads back with
user: null(lesson 6.7). - End-to-end: one journey after each deploy: create a user, order a product, move the order to processing (lesson 6.6).
Consumer-driven vs spec-driven contracts
There are two common ways to run layer 3:
- Consumer-driven (Pact is the best-known tool): each consumer records the requests it makes and the parts of the response it uses; the provider replays those expectations in its own build. Precise about what consumers really need, and it needs both sides to adopt the tool.
- Spec-driven: the provider's OpenAPI spec is the contract. Consumers generate mocks from it, and the provider is checked against it, with schema assertions or tools such as Schemathesis and Dredd. Easier to adopt, and only as precise as the spec.
Many teams start spec-driven and add consumer-driven contracts on their most critical integrations.
Microservices testing tools, by layer
| Layer | Open-source examples |
|---|---|
| Unit | JUnit, pytest, Jest, Go's testing package |
| Component | Rest Assured, supertest, Karate; WireMock, Prism or a mock server for neighbours |
| Contract | Pact, Spring Cloud Contract; Schemathesis, Dredd, Spectral for specs |
| Integration | Testcontainers, docker compose |
| End-to-end and load | Workflow-based API tools, k6 |
Microservices automation testing tools only pay off when each layer runs in the pipeline at the right moment: unit, component and contract on every merge; integration on merge or deploy; end-to-end after deploy.
Common mistakes
- An end-to-end-only strategy. Slow, flaky, and it tells you a journey broke without saying which service broke it.
- Hand-written mocks. They drift from the real service; generate them from the spec and regenerate on change.
- Contract checks only on one side. The provider must check too, or the consumer's mock goes stale.
- No ownership. Every service needs a team that owns its tests and its spec.
Mocks and a contract pack in Shift-Left API
Shift-Left API takes the spec-driven route: it imports each service's spec, generates tests whose assertions come from the response schema (status codes, field presence and types), and spins up mock servers from the same spec. It doesn't run consumer-driven contracts or a Pact broker, and its mocks are stateless, so treat them as component-level stand-ins.
To run the same tests against a real service and against its mock:
- Import
https://demo.totalshiftleft.ai/openapi/rest.json. Generate mocks for Products on the Mocks page and click Start Mock Server. - In Project Settings → Environment Settings, keep Development on the live sandbox and add an environment on the mock server's path-based URL (lesson 9.9).
- Make two tests on
GET /api/v1/products/{id}: the Wireless Mouse (aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa), expecting 200 and a product name; and00000000-0000-0000-0000-000000000000, expecting 404. - In Execution, create a Functional Test Run Pack with both tests. Test Run Packs need Professional, a trial or Enterprise.
- Run it with Override ticked and the environment set to Development, then again with the mock environment.
On Development, both pass. On the mock, the 200 test passes and the 404 test fails: a mock generated from the spec answers every request on that path with the documented success. That's the lesson of the layers in one result. A mock is good enough to test a consumer; only the real service can prove the provider. The same pack runs from CI (lesson 9.10 covers packs and scheduling), and the API contract testing page describes the contract checks in more detail.
Try it yourself
With a trial, build the two-test pack above and run it once per environment. Then open the pack's run history and compare the two pass rates.
Recap
- What is microservices testing: testing each service alone, the contracts between services, and a few journeys across them, in layers from many fast tests to few slow ones.
- A microservices testing example: test orders-service against mocks of users and catalog, check those services against their specs, and keep one cross-service journey.
- Microservices testing tools map to layers; mocks prove the consumer, contract checks prove the provider.
For the full strategy, tools comparison and a migration case study, read microservices testing: strategy, types, tools and examples.
Next: Track 7 begins with what is CI/CD in automation testing.
Try it: With a trial, make two tests for GET /api/v1/products/{id} (the Wireless Mouse, expecting 200; and id 00000000-0000-0000-0000-000000000000, expecting 404), put them in a Functional Test Run Pack, and run it twice: once with Override set to the Development environment, once set to an environment on your Products mock server's URL.
Frequently asked questions
What is a simple microservices testing example?+
Split a store into users, catalog and orders services. Test the orders service on its own with the users and catalog services replaced by mocks generated from their specs, check that the real users and catalog services still match those specs, and keep one end-to-end journey that places an order through all three. Each layer catches a different kind of break.
Which microservices testing tools cover which layer?+
Unit tests use the language's own framework. Component tests use an HTTP client plus WireMock, Prism or a mock server for neighbours. Contract tests use Pact for consumer-driven contracts, or schema checks and tools such as Schemathesis and Dredd against an OpenAPI spec. Testcontainers starts real dependencies, and k6 covers load.
What should microservices automation testing tools run in CI?+
On every merge to a service: its unit and component tests, and its contract checks against the specs it publishes and consumes. After deploying to a shared environment: a small end-to-end smoke set across services. Load and long journeys run on a schedule, not on every merge.
Related lessons
API integration testing checks the seams, such as what happens to an order when its user is deleted. Here's how it differs from API testing, the practices that keep it reliable, and a cross-resource test.
A mock API answers the way the real one is documented to, so you can test before the service exists or while it's down. Here's what a mock can prove, what it can't, and how to spin one up from a spec.
Turn a handful of tests into something that runs on its own. Build a Test Run Pack in Shift-Left API, schedule it for every night, run it now, and find every run in Reporting.
Read more on the blog
Microservices testing explained: the testing pyramid for distributed systems, a practical strategy framework, service isolation with mocks, contract testing, tools and worked examples.
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.