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