Skip to content

API Mocking with WireMock — Stubbing Responses, Stateful Behavior, and Record-Playback

DodaTech Updated 2026-06-28 4 min read

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

  1. What is a stub in WireMock? A: A predefined response that WireMock returns when a matching request is received.
  2. How do you match requests by JSON body? A: Use matchingJsonPath("$..field") or provide an exact JSON body template.
  3. What is record-playback? A: WireMock proxies requests to a real API and records responses, then replays them offline.
  4. How do you simulate a timeout in WireMock? A: Set fixed_delay_milliseconds to a value longer than your client's timeout.
  5. 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