Test Tools · API Testing

WireMock

A flexible HTTP mock server for integration and component testing. WireMock runs as a standalone process (or embedded in JVM tests) and simulates any HTTP API — returning canned responses, verifying request counts, adding latency, and simulating faults.

Overview

WireMock, created by Tom Akehurst and now maintained by the WireMock community, is an open-source HTTP stub and mock server. It intercepts HTTP requests sent by your system under test and returns pre-configured responses. This lets integration tests run entirely in isolation — no real external APIs, no network flakiness, no rate limits, no test data cleanup.

WireMock can be started as a standalone JAR (java -jar wiremock.jar --port 8080), spun up as a Docker container, or embedded directly inside a JUnit or TestNG test class. Stubs are defined either as JSON files dropped into a mappings/ directory or programmatically via a fluent Java DSL. The admin REST API lets you configure stubs at runtime from any language.

Beyond simple stub-and-respond, WireMock supports stateful scenarios (a sequence of states that advance on each matching request), fixed and random latency, connection resets, chunked dribble responses, and request journal querying so you can assert exactly what your system sent.

WireMock vs alternatives

WireMock MSW Pact Manual Mocks
Runs as separate server Yes No No No
Browser support No Yes No Yes
Stateful scenarios Yes Limited No Manual
Latency simulation Yes Limited No No
Request verification Yes Limited Yes No
Best for Integration tests, Java backends Frontend component tests Contract verification Simple unit tests

When WireMock is the right choice

Use WireMock when your service makes outbound HTTP calls that you need to control, verify, or make unreliable on demand.

Use WireMock when…

  • Microservice integration testing: Your service calls an external API (IRD, ACC, a payment gateway). WireMock runs that external API locally so your tests never touch real endpoints.
  • Latency and chaos testing: Simulate a slow upstream (AddFixedDelay) or a flaky one (random failures) to verify your retry logic and timeout handling hold up.
  • Stateful scenario testing: First call returns Pending, second call returns Approved — testing a polling pattern without a real backend that transitions state.
  • CI isolation: You want integration tests that pass with zero external network access, so they are fast and repeatable in any pipeline.

Do NOT use WireMock when…

  • Frontend-only component tests: Use MSW instead — it intercepts at the service-worker level in the browser, with no separate process needed.
  • Verifying the API contract is correct: Use Pact instead. WireMock only verifies your system sends the right request; Pact verifies the provider can actually honour the contract.
  • Pure unit tests: If the HTTP call is the only dependency, a simple in-memory mock or test double is lighter and faster.

Quick start

Maven dependency (pom.xml)
<dependency>
  <groupId>org.wiremock</groupId>
  <artifactId>wiremock-standalone</artifactId>
  <version>3.9.1</version>
  <scope>test</scope>
</dependency>

WireMock also runs as a Docker container or standalone JAR — no JVM test framework required when you are stubbing from another language.

JSON stub — POST /api/claims/submit with body matching
// mappings/submit-claim.json
{
  "request": {
    "method": "POST",
    "url": "/api/claims/submit",
    "bodyPatterns": [
      { "matchesJsonPath": "$.claimType", "contains": "ACC32" }
    ]
  },
  "response": {
    "status": 200,
    "headers": { "Content-Type": "application/json" },
    "jsonBody": {
      "claimId": "CLM-20260001",
      "status": "Received",
      "estimatedProcessingDays": 5
    }
  }
}
Latency simulation — 2-second fixed delay
// Java DSL (inside a JUnit test class)
stubFor(post(urlEqualTo("/api/claims/submit"))
    .willReturn(aResponse()
        .withStatus(200)
        .withHeader("Content-Type", "application/json")
        .withBody("{\"claimId\":\"CLM-20260001\",\"status\":\"Received\"}")
        .withFixedDelay(2000)));   // 2 000 ms delay

// Use RandomDelayDistribution for realistic jitter:
// .withRandomDelay(new UniformDistribution(500, 3000))
Stateful scenario — polling: Pending → Approved
// State 1: first GET returns Pending
stubFor(get(urlEqualTo("/api/claims/CLM-20260001"))
    .inScenario("ClaimApproval")
    .whenScenarioStateIs(Scenario.STARTED)
    .willReturn(okJson("{\"status\":\"Pending\"}"))
    .willSetStateTo("Approved"));

// State 2: second GET returns Approved
stubFor(get(urlEqualTo("/api/claims/CLM-20260001"))
    .inScenario("ClaimApproval")
    .whenScenarioStateIs("Approved")
    .willReturn(okJson("{\"status\":\"Approved\",\"paymentDate\":\"2026-07-04\"}")));

// After your code polls twice, assert:
verify(2, getRequestedFor(urlEqualTo("/api/claims/CLM-20260001")));
Pro tip: The verify() call queries WireMock’s request journal. Use it to assert your system sent the correct headers, body, and number of retries — not just that it received the right response.

NZ use case — MSD benefit calculator

The Ministry of Social Development’s benefit calculator service calls an external income verification API to check a client’s declared wages against IRD records before computing the Jobseeker Support entitlement. The income verification endpoint is operated by a third party and is unavailable in development and CI environments.

The integration test suite uses WireMock to stub the income verification API. Three stubs cover the scenarios the calculator must handle:

  • Happy path: IRD confirms income matches declaration → calculator proceeds to entitlement computation.
  • Discrepancy: IRD returns a higher income figure → calculator flags for manual review and does not pay automatically.
  • Timeout: WireMock adds a 35-second fixed delay, exceeding the 30-second client timeout → calculator falls back to manual processing and logs a timeout event.

All three integration tests run in CI in under four seconds with no external network access. The team also uses the request journal to verify the calculator always sends the client’s IRD number in the correct format and never logs it to the audit trail.

Platforms & Integrations

WireMock runs on any platform with a JVM (Java 11+). The standalone JAR and Docker image make it language-agnostic — .NET, Python, Node.js, and Go test suites all configure stubs via the admin REST API.

Windows macOS Linux Docker Java Kotlin JUnit 5 TestNG Maven Gradle Spring Boot GitHub Actions Jenkins GitLab CI Testcontainers

Pricing

TierCostIncludes
Open SourceFreeFull WireMock, standalone JAR, Docker image, Java DSL, JSON mappings, admin API
WireMock CloudFrom $19/moHosted mock APIs, team sharing, traffic capture, no local server needed

Pros & Cons

Pros

  • Runs as a real HTTP server — no bytecode manipulation or framework magic
  • Stateful scenarios cover polling, retry, and multi-step flows
  • Request journal enables precise assertion of outbound calls
  • Docker image makes it usable from any language, not just Java
  • Fault simulation (connection reset, empty response, chunked dribble) for chaos testing
  • Free and open source (Apache 2.0)

Cons

  • Adds a process to your test environment — more moving parts than an in-memory mock
  • JSON stub files can proliferate and become hard to maintain
  • No browser intercept — cannot mock requests made by JavaScript in a browser
  • Stateful scenario API is not intuitive for complex multi-branch flows
  • Does not validate that your stubs reflect the real API — use Pact for that

Alternatives

  • Pact — Consumer-driven contract testing. Use alongside WireMock: WireMock for integration tests, Pact to keep stubs honest against the real provider.
  • MSW (Mock Service Worker) — Browser-native request interception via service workers. The right choice for React, Vue, or Angular component tests.
  • Mountebank — Polyglot service virtualization. Supports HTTP, HTTPS, TCP, and SMTP stubs. Heavier and less maintained than WireMock.
  • Testcontainers — Spin up WireMock (or any Docker image) inside a JUnit test lifecycle with WireMockContainer. Combines well with WireMock rather than replacing it.

Self-check

Click each question to reveal the answer.

Q1: What is the difference between a stub and a mock in the context of WireMock?

A stub provides a canned response to a matching request — it replaces a real dependency. A mock goes further: it also records what requests were made so you can assert on them afterwards. WireMock is both: it stubs responses and, via the request journal, lets you verify the exact calls your system under test made (count, headers, body). Most WireMock usage is stubs-plus-verification, which is the mock pattern.

Q2: Your integration test hits a timeout stub but the test still passes. What is the most likely cause?

The client timeout in your system under test is longer than the fixed delay in WireMock, so the response eventually arrives and the happy-path code runs. Fix by either increasing the WireMock delay beyond the client timeout, or by using withFault(Fault.CONNECTION_RESET_BY_PEER) for an immediate connection failure instead of a delay.

Q3: When would you use a stateful scenario instead of two separate stubs for the same URL?

When the same endpoint must return different responses on successive calls from the same test run — for example, a polling endpoint that returns Pending on the first call and Approved on the second. Two separate stubs on the same URL and method would conflict; WireMock cannot reliably choose between them. Scenarios let you define an explicit sequence with named states.

Q4: Why is it important to pair WireMock with Pact (or another contract tool) in a microservices project?

WireMock stubs are written by the consumer team and reflect what they believe the API returns — but nothing enforces that the real provider actually returns that. Over time, stubs drift from reality. Pact solves this by publishing the consumer’s expectations as a contract that the provider’s CI pipeline must verify. Together, WireMock gives you fast isolated integration tests; Pact keeps those stubs honest against the real provider.

Q5: A teammate says “We should just use WireMock for our React component tests so everything is consistent.” How do you respond?

WireMock runs as a separate HTTP server, which means browser-based component tests would need a running WireMock instance and would make real network calls from the browser to localhost. MSW (Mock Service Worker) intercepts fetch/XHR at the browser’s service-worker level with zero extra processes, works in both jsdom (Jest/Vitest) and a real browser, and is purpose-built for this use case. Reserve WireMock for your backend service integration tests; use MSW in the frontend.

Learn more