API Mocking with WireMock — Stubbing Responses, Stateful Behavior, and Record-Playback
In this tutorial, you will learn about API Mocking with WireMock. We cover key concepts, practical examples, and best practices to help you master this topic.
WireMock is a flexible API mocking library that creates HTTP stubs based on request matching, simulates latency and errors, supports stateful behavior, and can record responses from real APIs.
What You'll Learn
- How to create WireMock stubs with URL, header, and body matching
- Simulating delays, errors, and stateful API behavior
- Recording and replaying real API responses
Why It Matters
External APIs are unreliable in test environments. Mocking them removes network dependency, enables offline testing, and simulates edge cases that real APIs rarely trigger.
Real-World Use
A payment processing system depends on a third-party gateway. Using WireMock, the team mocks all gateway responses including success, decline, timeout, and server error, achieving 95% test coverage without real transactions.
flowchart LR
A[Test Suite] --> B[WireMock Server]
B --> C[Stub Responses]
C --> D[System Under Test]
D --> E[Assertions]
Creating a Basic Stub
Start WireMock and define a stub for GET /products.
import requests
from wiremock.testing import WireMockServer
wm = WireMockServer(port=8089)
wm.start()
# Create stub
wm.stub_for(
method="GET",
url="/products/1",
status=200,
body='{"id": 1, "name": "Laptop", "price": 999.99}'
)
# Test against mock
resp = requests.get("http://localhost:8089/products/1")
assert resp.json()["name"] == "Laptop"
Expected output: Assertion passes because WireMock returns the stubbed response.
Request Matching with Headers
Match requests based on headers for more selective stubbing.
wm.stub_for(
method="POST",
url="/users",
headers={"Authorization": "Bearer valid-token"},
status=201,
body='{"id": 42, "name": "Alice"}',
)
# Valid token returns 201
resp1 = requests.post(
"http://localhost:8089/users",
headers={"Authorization": "Bearer valid-token"},
)
assert resp1.status_code == 201
# Invalid token returns 404 (no match found)
resp2 = requests.post(
"http://localhost:8089/users",
headers={"Authorization": "Bearer bad-token"},
)
assert resp2.status_code == 404
Expected output: First request returns 201, second returns 404.
Simulating Delays and Errors
Test how your application handles network failures and slow responses.
# Simulate 5-second delay
wm.stub_for(
method="GET",
url="/slow-endpoint",
status=200,
body="{}",
fixed_delay_milliseconds=5000,
)
# Simulate 500 error
wm.stub_for(
method="GET",
url="/broken-endpoint",
status=500,
body='{"error": "Internal Server Error"}',
)
Expected output: The slow endpoint takes 5 seconds and the broken endpoint returns 500.
Common Mistakes
| Mistake | Why It's Wrong |
|---|---|
| Mocking too broadly | Vague stubs match unintended requests and hide bugs |
| Not matching HTTP methods | A POST stub matches a GET request, causing false passes |
| Hardcoding response bodies | Tests break if the real API format changes |
| Not resetting state between tests | Stubs accumulate and cause cross-test contamination |
| Mocking only success cases | Error handling code goes untested |
| Ignoring request body matching | The same URL with different bodies needs different responses |
| Not using priority matching | Multiple matching stubs should use priority ordering |
Practice Questions
- What is a stub in WireMock? A: A predefined response that WireMock returns when a matching request is received.
- How do you match requests by JSON body?
A: Use
matchingJsonPath("$..field")or provide an exact JSON body template. - What is record-playback? A: WireMock proxies requests to a real API and records responses, then replays them offline.
- How do you simulate a timeout in WireMock?
A: Set
fixed_delay_millisecondsto a value longer than your client's timeout. - What is stub priority? A: When multiple stubs match, the one with the lowest priority number wins.
Challenge
Create a WireMock setup for a payment gateway with stubs for: successful payment (200), declined card (402), insufficient funds (403), server error (500), and timeout (no response for 10s). Write tests that verify your application handles each scenario correctly.
FAQ
How does WireMock differ from mocks in unittest?
WireMock is an HTTP server that intercepts real HTTP calls; unittest mocks replace function calls at the code level.
Can WireMock run in Docker?
Yes, the official WireMock Docker image (wiremock/wiremock) runs as a standalone server.
How do you reset WireMock between tests?
Call wm.reset_all() to remove all stubs and reset request journal.
Does WireMock support HTTPS?
Yes, WireMock generates a self-signed certificate and can serve HTTPS stubs.
What is WireMock's request journal?
A record of all received requests that you can query for verification.
How do you test that a specific request was made?
Use wm.verify(method="POST", url="/users") to check the request journal.
Can WireMock simulate stateful APIs?
Yes, use scenario states to simulate multi-step workflows like login then access protected resource.
Mini Project
Build a WireMock-based test suite for an order processing system that depends on: Product API (GET product by ID), Payment Gateway (POST payment with retry logic), Shipping API (POST create shipment). Mock all three with stubs for success, failure, and timeout scenarios. Test that the system retries payment on 503 and fails gracefully on invalid product.
What's Next
Next, learn about API test coverage analysis to measure how thoroughly your tests exercise your endpoints.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro