Why Mock APIs?
API mocking creates simulated versions of real APIs that return predefined responses. This is essential in modern development because:
Common Scenarios for Mocking
- Third-party API unavailability — the payment provider’s sandbox is down, but you need to test checkout
- API still in development — the backend team hasn’t finished the endpoint yet, but frontend needs to integrate
- Cost reduction — calling a paid API (Google Maps, OpenAI) thousands of times during testing is expensive
- Deterministic testing — real APIs may return different data each time; mocks return consistent data
- Edge case simulation — it’s hard to trigger a 500 error from a real API; mocks can simulate any response
- Performance testing — mock APIs can simulate slow responses, timeouts, and network errors
- Offline development — developers can work without internet connectivity
Stubs vs. Mocks vs. Fakes
| Term | Definition | Example |
|---|---|---|
| Stub | Returns predefined responses | Returns {id: 1, name: "Alice"} for any GET /users/1 |
| Mock | Stub + verifies expectations | Same as stub, but also verifies the request was made exactly once |
| Fake | Simplified working implementation | In-memory database instead of real PostgreSQL |
Introduction to WireMock
WireMock is the most popular API mocking tool in the Java ecosystem, but it works with any language via its HTTP API or standalone server.
Running WireMock
Standalone (any language):
# Download
wget https://repo1.maven.org/maven2/org/wiremock/wiremock-standalone/3.3.1/wiremock-standalone-3.3.1.jar
# Run
java -jar wiremock-standalone-3.3.1.jar --port 8080
# WireMock is now running at http://localhost:8080
Docker:
docker run -d -p 8080:8080 wiremock/wiremock:latest
Creating Your First Stub
Via JSON mapping file (place in mappings/ directory):
{
"request": {
"method": "GET",
"url": "/api/users/1"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"id": 1,
"name": "Alice Johnson",
"email": "alice@example.com",
"role": "admin"
}
}
}
Via HTTP API:
curl -X POST http://localhost:8080/__admin/mappings -d '{
"request": {
"method": "GET",
"urlPattern": "/api/users/[0-9]+"
},
"response": {
"status": 200,
"jsonBody": {"id": 1, "name": "Alice"}
}
}'
Now GET http://localhost:8080/api/users/1 returns the mocked response.
Request Matching
WireMock supports sophisticated request matching:
URL Matching
{"url": "/api/users/1"} // Exact match
{"urlPattern": "/api/users/[0-9]+"} // Regex match
{"urlPathPattern": "/api/users/.*"} // Path pattern
{"urlPath": "/api/users", "queryParameters": {"role": {"equalTo": "admin"}}}
Header Matching
{
"request": {
"method": "GET",
"url": "/api/data",
"headers": {
"Authorization": {"equalTo": "Bearer valid-token"},
"Accept": {"contains": "application/json"}
}
}
}
Body Matching
{
"request": {
"method": "POST",
"url": "/api/users",
"bodyPatterns": [
{"matchesJsonPath": "$.name"},
{"matchesJsonPath": "$.email"}
]
}
}
Advanced WireMock Features
Simulating Delays
{
"request": {"method": "GET", "url": "/api/slow"},
"response": {
"status": 200,
"fixedDelayMilliseconds": 3000,
"jsonBody": {"data": "delayed response"}
}
}
Simulating Errors
{
"request": {"method": "GET", "url": "/api/error"},
"response": {
"status": 500,
"jsonBody": {"error": "Internal Server Error"}
}
}
{
"request": {"method": "GET", "url": "/api/timeout"},
"response": {
"fault": "CONNECTION_RESET_BY_PEER"
}
}
Stateful Behavior (Scenarios)
Mock different responses based on state:
[
{
"scenarioName": "User lifecycle",
"requiredScenarioState": "Started",
"newScenarioState": "User created",
"request": {"method": "POST", "url": "/api/users"},
"response": {"status": 201, "jsonBody": {"id": 1, "name": "Alice"}}
},
{
"scenarioName": "User lifecycle",
"requiredScenarioState": "User created",
"request": {"method": "GET", "url": "/api/users/1"},
"response": {"status": 200, "jsonBody": {"id": 1, "name": "Alice"}}
}
]
Request Verification
Verify that expected requests were made:
# Verify a request was made
curl http://localhost:8080/__admin/requests/count -d '{
"method": "POST",
"url": "/api/users"
}'
# Response: {"count": 1}
# Get all recorded requests
curl http://localhost:8080/__admin/requests
Response Templating
Dynamic responses based on request data:
{
"request": {"method": "GET", "urlPattern": "/api/users/(.*)"},
"response": {
"status": 200,
"jsonBody": {
"id": "{{request.pathSegments.[2]}}",
"name": "User {{request.pathSegments.[2]}}"
},
"transformers": ["response-template"]
}
}
Mocking Strategies
Service Virtualization Pattern
For microservice architectures, mock external dependencies:
[Your Service] → [WireMock: Payment API]
→ [WireMock: Email API]
→ [Real: Database]
Contract-First Mocking
Generate mocks from OpenAPI specifications:
# WireMock can auto-generate stubs from OpenAPI
java -jar wiremock-standalone.jar --enable-stub-cors --record-mappings
Mock in CI/CD
# GitHub Actions example
services:
wiremock:
image: wiremock/wiremock:latest
ports:
- 8080:8080
volumes:
- ./tests/mocks:/home/wiremock
steps:
- name: Run integration tests
run: npm test
env:
API_URL: http://localhost:8080
Alternatives to WireMock
| Tool | Language | Best For |
|---|---|---|
| WireMock | Java/Any | Enterprise, complex matching |
| MockServer | Java/Any | Similar to WireMock |
| json-server | Node.js | Quick REST mock from JSON file |
| Prism | Any | Auto-mock from OpenAPI spec |
| MSW | JavaScript | Browser/Node.js request interception |
| Mountebank | Any | Multi-protocol (HTTP, TCP, SMTP) |
Hands-On Exercise
- Set up WireMock: Run WireMock standalone or via Docker. Create stubs for GET, POST, and DELETE operations.
- Request matching: Create stubs that respond differently based on query parameters, headers, and request body.
- Simulate failures: Create stubs for 500 errors, timeouts, and connection resets. Test how your client handles them.
- Verify requests: Use WireMock’s verification API to confirm that your client made the expected requests.
- Stateful mock: Create a scenario where POST creates a resource and subsequent GET returns it.
Key Takeaways
- API mocking simulates real API behavior for testing when the actual API is unavailable, costly, or unpredictable
- WireMock is the industry-standard mocking tool — it supports request matching, response templating, delays, faults, and stateful scenarios
- Stubs return predefined responses; mocks add verification that expected requests were actually made
- Use mocking for third-party APIs, APIs in development, edge case simulation, and CI/CD integration testing
- Response templating and stateful scenarios enable realistic mock behavior that closely mimics real APIs