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 (Revenue NZ, CoverNZ, 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 — Benefits NZ benefit calculator

The Benefits NZ benefit calculator service calls an external income verification API to check a client’s declared wages against Revenue NZ 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: Revenue NZ confirms income matches declaration → calculator proceeds to entitlement computation.
  • Discrepancy: Revenue NZ 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 Revenue NZ 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.

When to choose WireMock

A quick decision guide for NZ teams evaluating API mocking options.

Choose WireMock when… Choose something else when… Combine with…
Your backend service is Java or Kotlin and you want stubs configured with the same fluent DSL you write tests in Your tests run in a browser (React, Vue, Angular) — a separate HTTP server adds unnecessary complexity MSW for the frontend layer — let WireMock own backend integration tests and MSW own component tests
You need to simulate latency, connection resets, or fault conditions to test your retry and timeout logic You need to verify the real provider can honour your API expectations — WireMock stubs can drift silently from the actual contract Pact for contract enforcement — WireMock gives you fast isolated tests; Pact keeps those stubs honest
CI must run with zero external network access — third-party APIs (Revenue NZ, CoverNZ, payment gateways) cannot be called from your pipeline You only have one or two simple HTTP calls in a unit test — a lightweight in-memory test double (e.g. OkHttp MockWebServer) has less overhead Testcontainers (WireMockContainer) to manage WireMock lifecycle inside JUnit so no external process setup is needed
You need to test the same endpoint returning different responses on successive calls (polling, retry sequences, state machine flows) Your team is Node.js-only with no JVM toolchain — standing up a Java process in CI adds friction; consider nock or Polly.js instead Pact + WireMock Cloud for large teams where stubs need to be shared across squads without each team running their own server

What I would do

Practitioner judgment on tool adoption, team onboarding, and when to swap.

If…
I was joining CloudBooks’s payments integration team and the integration tests were hitting live Stripe and bank endpoints in CI — causing flaky failures and the occasional accidental charge
I would…
Wire WireMock into the test harness using WireMockExtension (JUnit 5) and build a small library of canonical stubs — one per provider response type (success, card decline, timeout, fraud hold). Store stubs in a shared test-fixtures/wiremock/ directory so every squad pulls from the same source of truth. Add a verify() assertion on every test that submits a payment to confirm the correct idempotency key header was sent — the bug that keeps biting payment teams is a missing or duplicated key.
If…
I was testing TransitNZ’s tolling system integration with the TransitNZ vehicle register API, which has strict rate limits and is only reachable from the production network
I would…
Run WireMock as a Testcontainers instance inside the CI pipeline and capture a real response from the TransitNZ sandbox (one-off, authorised) using WireMock’s record mode (--record-mappings). Commit those recorded mappings to the repo. Now CI has realistic stubs that mirror the actual response shape without ever touching the production network. Pair this with a quarterly Pact consumer test against the TransitNZ sandbox to detect schema drift before it causes a production incident.
If…
I was onboarding a QA engineer at Harbour Bank who had never used WireMock and the team relied on JSON stub files scattered across fifteen subdirectories with no naming convention
I would…
Start the new engineer with three tasks in order: (1) write a single stub using the Java DSL and verify it with verify() so they understand the request journal; (2) convert that stub to JSON and place it in a mappings/ directory so they see both authoring modes; (3) write a stateful scenario with two states so they learn the sequencing model. Only after those three can they touch the existing stub library. I would also spend one session creating a naming convention like {service}-{endpoint}-{variant}.json and renaming the fifteen directories to a flat structure — maintainable stub libraries are the number one thing that separates teams that love WireMock from teams that abandon it.

The bottom line: WireMock earns its keep on teams where integration test reliability and CI speed matter more than convenience. The moment you find yourself maintaining more than a dozen stubs, invest in a naming convention and a shared fixture library — otherwise the stubs become the thing you test around, not the thing that helps you test.

Interview questions

Questions you are likely to get if you list WireMock on your CV — with what interviewers are really testing for.

What is WireMock and why would you use it instead of hitting a real API in your integration tests?

What they’re really testing: Whether you understand the purpose of test doubles and can articulate the tradeoffs between test isolation and test realism — not just that you know the tool name.

Strong answer covers: WireMock is an HTTP stub and mock server that intercepts outbound calls so tests run in isolation without real network dependencies; you get speed, repeatability, and no risk of hitting rate limits or leaving test data on a live service (e.g. an Revenue NZ or CoverNZ API in NZ government projects); the tradeoff is stubs can drift from the real contract, which is why you pair WireMock with Pact.

When would you choose WireMock over MSW (Mock Service Worker) for API mocking?

What they’re really testing: Whether you can match the right tool to the right layer of the stack, and whether you understand that choosing wrongly adds unnecessary process overhead or misses browser-level interception entirely.

Strong answer covers: WireMock is the right choice for backend service integration tests (Java, Kotlin, or any language via the Docker image) where you need fault simulation, latency injection, or the request journal; MSW intercepts at the browser service-worker level and is purpose-built for React/Vue component tests; a mature NZ fintech or government team often runs both — WireMock for the Spring Boot service layer, MSW for the frontend.

You’re working at a Wellington-based insurer that integrates with a Ministry of Health API for claims verification. The API is only reachable from the production network and has strict rate limits. How would you structure your integration tests?

What they’re really testing: Whether you can apply WireMock to a realistic NZ constraint (restricted network, government API, Privacy Act data) and choose the right recording and maintenance strategy.

Strong answer covers: Use WireMock’s record mode (--record-mappings) once against a sandbox endpoint with authorised credentials to capture realistic response shapes, commit those mappings to the repo, then run WireMock via Testcontainers in CI with zero external network access; note that recorded responses must be scrubbed of any real NHI numbers or personal health data before committing (Privacy Act 2020 obligation); schedule a quarterly Pact consumer test against the Ministry sandbox to catch schema drift.

Your timeout test passes locally but fails in CI — the service handles the timeout gracefully locally but throws an unhandled exception in the pipeline. What do you investigate first?

What they’re really testing: Whether you can debug WireMock timing interactions and understand the difference between a delay-based timeout and a connection-level fault — a common source of intermittent CI failures.

Strong answer covers: Check whether the WireMock fixed delay is actually longer than the client’s configured timeout in CI (environment variables or config files may differ between local and pipeline); if the delay is shorter than the timeout, the response arrives and the happy path runs; also consider switching from withFixedDelay() to withFault(Fault.CONNECTION_RESET_BY_PEER) for a guaranteed immediate failure that is not timing-dependent; check the WireMock request journal to confirm whether the request even reached the stub.

How would you structure WireMock stubs across a large microservices team so they remain maintainable as the real APIs evolve?

What they’re really testing: Whether you think beyond individual test setup to team-scale maintainability — stub sprawl and drift are the two failure modes that make teams abandon WireMock.

Strong answer covers: Store stubs in a shared test-fixtures/wiremock/ directory with a consistent naming convention such as {service}-{endpoint}-{variant}.json; build a small Java builder library so teams configure stubs via typed methods rather than raw JSON strings (reduces typos, easier refactoring); pair every stub set with a Pact consumer contract so provider CI verifies the stubs against the real service; in a NZ context like a multi-squad CloudBooks or Harbour Bank platform team, consider WireMock Cloud to share stubs across squads without each team running their own server.

Learn more