Advanced
Chapter 18 · 12 min read
Mocking & Service Virtualization
Mock API responses for isolated testing, use tools like WireMock and nock, and create virtual services for unavailable dependencies.
API Mocking & Service Virtualization
When testing, you don't always have access to real APIs. Third-party services might be down, rate-limited, or expensive. Mocking lets you simulate API behavior for fast, reliable, isolated testing.
When to Mock
- Third-party APIs you don't control
- APIs still under development
- Testing error scenarios (500 errors, timeouts)
- CI/CD pipelines without external access
- Performance testing without hitting real servers
Mocking Libraries
Each language has powerful mocking tools: nock (JavaScript), WireMock (Java), and responses (Python). They intercept HTTP calls and return predefined responses.
mocking.test.js
// Using nock to mock HTTP calls
// npm install nock
import nock from 'nock';
// Mock a GET endpoint
nock('https://api.example.com')
.get('/users/1')
.reply(200, {
id: 1,
name: 'Mocked User',
email: 'mock@example.com'
});
// The actual fetch call hits the mock, not the real server
const response = await fetch('https://api.example.com/users/1');
const user = await response.json();
console.assert(user.name === 'Mocked User');
console.assert(response.status === 200);
// Mock error scenarios
nock('https://api.example.com')
.get('/users/999')
.reply(404, { error: 'User not found' });
const errorResp = await fetch('https://api.example.com/users/999');
console.assert(errorResp.status === 404);
// Mock with delay (simulate slow API)
nock('https://api.example.com')
.get('/slow-endpoint')
.delay(2000)
.reply(200, { data: 'delayed response' });
// Mock POST with body matching
nock('https://api.example.com')
.post('/users', { name: 'New User', email: 'new@test.com' })
.reply(201, { id: 42, name: 'New User', email: 'new@test.com' });
const createResp = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'New User', email: 'new@test.com' })
});
const created = await createResp.json();
console.assert(created.id === 42);
// Mock server error
nock('https://api.example.com')
.get('/unstable')
.reply(500, { error: 'Internal Server Error' });
nock.cleanAll(); // Clean up
console.log('All mock tests passed!');
WireMockTest.java
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import org.testng.annotations.*;
public class WireMockTest {
private WireMockServer wireMock;
@BeforeClass
public void startMockServer() {
wireMock = new WireMockServer(WireMockConfiguration.options().port(8089));
wireMock.start();
configureFor("localhost", 8089);
}
@AfterClass
public void stopMockServer() {
wireMock.stop();
}
@Test
public void testMockedGetEndpoint() {
// Set up mock response
stubFor(get(urlEqualTo("/users/1"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"id\": 1, \"name\": \"Mocked User\"}")));
// Test hits mock server
given()
.baseUri("http://localhost:8089")
.when()
.get("/users/1")
.then()
.statusCode(200)
.body("name", equalTo("Mocked User"));
}
@Test
public void testMockedError() {
stubFor(get(urlEqualTo("/users/999"))
.willReturn(aResponse()
.withStatus(404)
.withBody("{\"error\": \"Not found\"}")));
given().baseUri("http://localhost:8089")
.when().get("/users/999")
.then().statusCode(404);
}
@Test
public void testMockedSlowResponse() {
stubFor(get(urlEqualTo("/slow"))
.willReturn(aResponse()
.withStatus(200)
.withFixedDelay(2000)
.withBody("{\"data\": \"delayed\"}")));
given().baseUri("http://localhost:8089")
.when().get("/slow")
.then()
.statusCode(200)
.time(greaterThan(1500L));
}
}
// Add to pom.xml:
// <dependency>
// <groupId>org.wiremock</groupId>
// <artifactId>wiremock-standalone</artifactId>
// <version>3.5.2</version>
// <scope>test</scope>
// </dependency>
test_mocking.py
"""Mock API responses using the 'responses' library"""
# pip install responses
import requests
import responses
import pytest
@responses.activate
def test_mocked_get():
"""Mock a GET endpoint"""
responses.add(
responses.GET,
'https://api.example.com/users/1',
json={'id': 1, 'name': 'Mocked User', 'email': 'mock@test.com'},
status=200
)
response = requests.get('https://api.example.com/users/1')
assert response.status_code == 200
assert response.json()['name'] == 'Mocked User'
@responses.activate
def test_mocked_error():
"""Mock error responses"""
responses.add(
responses.GET,
'https://api.example.com/users/999',
json={'error': 'User not found'},
status=404
)
response = requests.get('https://api.example.com/users/999')
assert response.status_code == 404
@responses.activate
def test_mocked_post():
"""Mock POST with body validation"""
responses.add(
responses.POST,
'https://api.example.com/users',
json={'id': 42, 'name': 'New User'},
status=201
)
response = requests.post(
'https://api.example.com/users',
json={'name': 'New User', 'email': 'new@test.com'}
)
assert response.status_code == 201
assert response.json()['id'] == 42
# Verify the request was made correctly
assert len(responses.calls) == 1
assert 'New User' in responses.calls[0].request.body
@responses.activate
def test_mocked_server_error():
"""Simulate server errors"""
responses.add(
responses.GET,
'https://api.example.com/unstable',
json={'error': 'Internal Server Error'},
status=500
)
response = requests.get('https://api.example.com/unstable')
assert response.status_code == 500
API Testing
Advanced
Mocking & Service Virtualization
Written by PV
© 2026 All Rights Reserved