Q17 of 40 · Karate

Compare Karate's Mock Server to WireMock — when would you choose each?

KarateMidkaratemock-serverwiremockmockingapi-testing

Short answer

Short answer: Karate Mock Server is in-process (same JVM) and stubs responses using feature files — ideal when tests and mock co-locate. WireMock runs as a standalone server, better for integration tests where the real application under test calls an external dependency. Use Karate Mock for co-located API tests; WireMock when the real app server needs a stub.

Detail

Karate Mock Server:

  • Runs in the same JVM as the test
  • Stubs defined in a .feature file using pathMatches and methodIs predicates
  • Started programmatically: Server mock = Karate.startMock("classpath:mocks/payment.feature").port(9999)
  • Best for: testing Karate scenarios that call a dependency you want to control; contract-testing style stubs
# mocks/payment.feature (stub definition)
Feature: Payment mock
  Scenario: pathMatches('/payments') && methodIs('post')
    * def responseStatus = 200
    * def response = { transactionId: 'mock-tx-1', status: 'APPROVED' }

WireMock:

  • Runs as a separate HTTP server process (or embedded via WireMockServer)
  • Configured with Java fluent API or JSON stub files
  • Best for: integration tests where your real application server (Spring Boot, etc.) needs to call a stubbed external API
  • Works with any test library (REST Assured, Karate, plain JUnit)

Decision guide:

Scenario Choose
Karate tests a service that calls a third-party API Karate Mock Server
REST Assured tests your service; your service calls a third-party WireMock
You need request verification (was the right request sent?) WireMock (verify() API)
Cross-language team, stub must work with any framework WireMock

// EXAMPLE

KarateMockTest.java

// Karate Mock Server — started in JUnit 5 setup
class PaymentApiMockTest {
    static Server paymentMock;

    @BeforeAll
    static void startMock() {
        paymentMock = Karate.startMock("classpath:mocks/payment-gateway.feature").port(9999);
        // Set env var so karate-config.js routes to the mock
        System.setProperty("payment.gateway.url", "http://localhost:9999");
    }

    @AfterAll
    static void stopMock() { paymentMock.stop(); }

    // Karate features that call the checkout service will have
    // the checkout service route to localhost:9999 (the mock)
    @Test
    void runCheckoutTests() {
        Results results = Runner.path("classpath:features/checkout").parallel(2);
        assertThat(results.getFailCount()).isZero();
    }
}

// mocks/payment-gateway.feature (stub)
// Scenario: pathMatches('/charge') && methodIs('post')
//   * def responseStatus = 200
//   * def response = { status: 'APPROVED', txId: '#(karate.uuid())' }

// WHAT INTERVIEWERS LOOK FOR

Clear distinction of in-process vs standalone, the use case where each wins, and the pathMatches/methodIs predicate syntax for Karate stubs. Knowing WireMock's verify() API for asserting the outbound request was sent correctly is a senior detail.

// COMMON PITFALL

Using Karate Mock Server for integration tests where the real application runs in a separate process — the mock runs in the test JVM, not the application JVM, so the application can't reach it without network plumbing.