Skip to main content

EXTENSIONS

Test Doubles and Mocking

Create standalone mock servers with stateful behavior for API testing, consumer-driven contracts, and microservice development without external dependencies.

On this page:

Request Matching

Matching Predicates

Karate provides helper functions for request matching:

FunctionDescriptionExample
pathMatches()Match request paths with path parameterspathMatches('/users/{id}')
methodIs()Check HTTP method (recommended)methodIs('post')
paramExists()Check if query parameter existsparamExists('name')
paramValue()Get single query parameter valueparamValue('limit')
typeContains()Match Content-Type headertypeContains('xml')
acceptContains()Match Accept headeracceptContains('json')
headerContains()Check header contentsheaderContains('Authorization', 'Bearer')
bodyPath()Query request body using JsonPath/XPathbodyPath('$.username')

Request Variables

Available variables for inspecting incoming requests:

VariableDescriptionExample Value
requestRequest body (parsed as JSON/XML, or string){ "name": "John" }
requestBytesRaw request body as bytes (for binary content)[byte array]
requestMethodHTTP method in uppercaseGET, POST
requestPathPath without query string/users/1
requestUriPath with query string/users?page=2
requestUrlBaseProtocol, host, and porthttp://localhost:8080
requestHeadersAll headers (Map of Lists){ 'Content-Type': ['application/json'] }
requestParamsQuery parameters (Map of Lists){ 'page': ['2'] }
requestPartsMultipart parts for file uploads{ 'file': [{ filename: '...' }] }
pathParamsPath parameters from URL pattern{ 'id': '1' }
Best Practice

Use helper functions like methodIs('post') and paramValue('page') instead of accessing raw variables directly.

Basic Mock Server

Simple HTTP Mock

Create a basic mock server that responds to requests:

Gherkin
Feature: Simple user mock

Background:
* def users = { '1': { id: 1, name: 'John Doe' } }

Scenario: pathMatches('/users/{id}') && methodIs('get')
* def user = users[pathParams.id]
* def response = user || { error: 'Not found' }
* def responseStatus = user ? 200 : 404

This mock returns predefined user data or a 404 error.

Starting the Mock Server

Start the mock server within a test:

Gherkin
Feature: Test with user service mock

Background:
* def mock = karate.start('user-service-mock.feature')
* url 'http://localhost:' + mock.port

Scenario: Get user by ID
Given path 'users', '1'
When method get
Then status 200
And match response == { id: 1, name: 'John Doe' }

Multiple Endpoints

Add GET and POST endpoints to your mock:

Gherkin
Feature: User service with multiple endpoints

Background:
* def users = { '1': { id: 1, name: 'John Doe', email: 'john@example.com' } }

Scenario: pathMatches('/users/{id}') && methodIs('get')
* def user = users[pathParams.id]
* def response = user || { error: 'User not found' }
* def responseStatus = user ? 200 : 404

Scenario: pathMatches('/users') && methodIs('post')
* def newUser = request
* def newId = (karate.sizeOf(users) + 1) + ''
* def responseStatus = 400
* if (newUser.name && newUser.email) users[newId] = karate.merge(newUser, { id: ~~newId })
* if (newUser.name && newUser.email) response = users[newId]
* if (newUser.name && newUser.email) responseStatus = 201
* if (responseStatus == 400) response = { error: 'Missing required fields' }

Stateful Mocks

Product Catalog Mock

Create a mock with shared state across requests:

Gherkin
Feature: Product catalog mock

Background:
* def products = { '1': { id: 1, name: 'Laptop', price: 999 }, '2': { id: 2, name: 'Mouse', price: 29 } }

Scenario: pathMatches('/products') && methodIs('get')
* def response = karate.valuesOf(products)

Scenario: pathMatches('/products/{id}') && methodIs('get')
* def product = products[pathParams.id]
* def response = product || { error: 'Product not found' }
* def responseStatus = product ? 200 : 404

CRUD Mock

Implement create, read, update, delete operations with shared state:

Gherkin
Feature: CRUD mock

Background:
* def nextId = 1
* def items = {}

Scenario: pathMatches('/items') && methodIs('post')
* def item = request
* item.id = nextId
* items[nextId + ''] = item
* nextId = nextId + 1
* def response = item
* def responseStatus = 201

Scenario: pathMatches('/items/{id}') && methodIs('get')
* def item = items[pathParams.id]
* def response = item || { error: 'Not found' }
* def responseStatus = item ? 200 : 404

Scenario: pathMatches('/items/{id}') && methodIs('delete')
* def item = items[pathParams.id]
* if (item) delete items[pathParams.id]
* def responseStatus = item ? 204 : 404

Catch-All Scenario

Always include a catch-all scenario as the last one to handle unmatched requests. An empty scenario description evaluates to true:

Gherkin
Feature: Mock with catch-all

Background:
* def users = { '1': { id: 1, name: 'John' } }

Scenario: pathMatches('/users/{id}') && methodIs('get')
* def response = users[pathParams.id] || { error: 'Not found' }
* def responseStatus = users[pathParams.id] ? 200 : 404

Scenario:
# Catch-all: returns 404 for any unmatched request
* def response = { error: 'Endpoint not found' }
* def responseStatus = 404

Response Configuration

Status Codes and Headers

Control mock responses using built-in variables:

VariableDescriptionDefault
responseResponse body (JSON, XML, string, or bytes)''
responseStatusHTTP status code200
responseHeadersResponse headers as JSON object{}
responseDelayDelay in milliseconds before responding0
Gherkin
Feature: Response configuration

Scenario: pathMatches('/api/data')
* def response = { message: 'Created successfully' }
* def responseStatus = 201
* def responseHeaders = { 'X-Request-Id': 'abc123', 'Cache-Control': 'no-cache' }

Simulating Latency

Add realistic network delays to test timeout handling and loading states:

Gherkin
Feature: Delayed responses

Scenario: pathMatches('/slow-api')
* def responseDelay = 2000
* def response = { data: 'delayed response' }

For random delays across all scenarios, use configure afterScenario:

Gherkin
Feature: Random delay mock

Background:
* configure afterScenario = function(){ karate.set('responseDelay', 100 + Math.random() * 500) }

Scenario: pathMatches('/api/data')
* def response = { message: 'Response with random 100-600ms delay' }

Starting Mock Servers

Within a Karate Test

Use karate.start() to launch a mock server from within a feature file. The mock starts on a random available port:

Gherkin
Feature: Test with embedded mock

Background:
* def mock = karate.start('classpath:mocks/user-mock.feature')
* url 'http://localhost:' + mock.port

Scenario: Call mock endpoint
Given path 'users', 1
When method get
Then status 200
And match response.name == '#string'

For more control, pass a JSON configuration:

Gherkin
Feature: Mock with options

Background:
* def mock = karate.start({ mock: 'user-mock.feature', port: 8090 })
* url 'http://localhost:8090'
OptionDescription
mockPath to mock feature file (required)
portFixed port number (default: random)
sslEnable HTTPS (default: false)
certSSL certificate path
keySSL private key path

Java API

Embed mocks in JUnit tests using MockServer:

Java
import com.intuit.karate.core.MockServer;

public class MyTest {
static MockServer mockServer;

@BeforeAll
static void setup() {
mockServer = MockServer
.feature("classpath:mocks/user-mock.feature")
.http(0) // Random port
.build();
}

@AfterAll
static void cleanup() {
mockServer.stop();
}

@Test
void testWithMock() {
int port = mockServer.getPort();
// Use port in your tests
}
}

Proxy Mode

Use karate.proceed() to forward requests to real backend services. This enables "AOP for web services" - you can intercept, modify, or conditionally stub requests.

Forwarding Requests

Forward all matching requests to a backend service:

Gherkin
Feature: API proxy

Scenario: pathMatches('/api/users')
* karate.proceed('https://jsonplaceholder.typicode.com')

After karate.proceed() returns, response and responseHeaders contain the backend's response. You can modify them before returning to the client.

Modifying Proxied Responses

Intercept and enrich responses from the backend:

Gherkin
Feature: Response enrichment proxy

Scenario: pathMatches('/api/users/{id}')
* karate.proceed('https://jsonplaceholder.typicode.com')
# Add metadata to response
* response.cached = false
* response.timestamp = new Date().toISOString()

Conditional Stubbing

Stub some requests while forwarding others:

Gherkin
Feature: Selective proxy

Background:
* def backendUrl = 'https://jsonplaceholder.typicode.com'

Scenario: pathMatches('/api/users/99999')
# Stub non-existent user for testing
* def response = { id: 99999, name: 'Test User' }

Scenario: pathMatches('/api/users/{id}')
# Forward all other user requests to real backend
* karate.proceed(backendUrl)

Server Lifecycle

Understanding the mock server lifecycle is essential for building effective mocks.

Background vs Scenario

Unlike normal Karate tests, mock servers have a different execution model:

PhaseNormal KarateMock Server
BackgroundRuns before each ScenarioRuns once on startup
ScenarioRuns sequentiallyEvaluated per incoming request

Request Matching

For each incoming HTTP request:

  1. Scenario expressions are evaluated in order from top to bottom
  2. The first scenario whose expression evaluates to true is executed
  3. If no scenario matches, no response is returned (connection timeout)
Scenario Order Matters

Place more specific scenarios before general ones. For example, put pathMatches('/users/admin') before pathMatches('/users/{id}').

Using karate.abort()

Stop scenario execution without returning a response:

Gherkin
Feature: Protected endpoint

Scenario: pathMatches('/protected')
* def auth = karate.request.header('authorization')
* if (!auth) karate.abort()
* def response = { message: 'Authorized access' }

Aborted scenarios result in connection timeout for the client - useful for simulating authentication failures.

CORS and Headers

Enable CORS

For browser-based testing, enable CORS with a single line. This automatically adds Access-Control-Allow-Origin: * and related headers:

Gherkin
Feature: Browser-friendly mock

Background:
* configure cors = true

Scenario: pathMatches('/api/data')
* def response = { message: 'CORS enabled' }

Global Response Headers

Set headers that apply to all responses:

Gherkin
Feature: Mock with global headers

Background:
* configure responseHeaders = { 'Content-Type': 'application/json', 'X-Powered-By': 'Karate' }

Scenario: pathMatches('/api/data')
* def response = { message: 'Has global headers' }

Scenario-level responseHeaders override global settings for individual endpoints.

Error Simulation

Test error handling by returning various HTTP error codes:

Gherkin
Feature: Error simulation

Scenario: pathMatches('/api/error/400')
* def response = { error: 'Bad Request', message: 'Invalid input' }
* def responseStatus = 400

Scenario: pathMatches('/api/error/500')
* def response = { error: 'Internal Server Error' }
* def responseStatus = 500

Scenario: pathMatches('/api/timeout')
* def responseDelay = 30000
* def response = { message: 'This will timeout most clients' }

File Uploads

Handle multipart file uploads using requestParts:

Gherkin
Feature: File upload mock

Scenario: pathMatches('/upload') && methodIs('post')
* def filePart = requestParts['file'][0]
* def response =
"""
{
filename: '#(filePart.filename)',
contentType: '#(filePart.contentType)',
size: '#(filePart.value.length)'
}
"""
* def responseStatus = 201

Each part in requestParts contains: name, filename, contentType, charset, transferEncoding, and value (raw bytes).

Standalone Mock Server

Run mocks as standalone servers from the command line. Download the Karate JAR or use jbang.

Using jbang

The easiest way to run mocks without any build setup:

# Install jbang: https://www.jbang.dev

# Run a mock server
jbang karate@karatelabs -m mock.feature -p 8080

# With SSL
jbang karate@karatelabs -m mock.feature -p 8443 -s

# Hot reload during development
jbang karate@karatelabs -m mock.feature -p 8080 -W

Using the JAR

# Basic server
java -jar karate.jar -m mock.feature -p 8080

# Multiple mock files (evaluated in order)
java -jar karate.jar -m users.feature -m orders.feature -p 8080

# With environment variable
java -jar karate.jar -m mock.feature -p 8080 -e staging

Command-Line Options

OptionDescription
-mMock feature file (can specify multiple)
-pPort number
-sEnable SSL (auto-generates certificate if none provided)
-cSSL certificate file (PEM format)
-kSSL private key file (PEM format)
-eSet karate.env value
-WWatch mode - hot reload on file changes
--keep-original-headersPreserve header case (for HTTP/1 compatibility)

Stopping a Running Server

Send a GET request to the admin endpoint to gracefully stop the server:

# Stop HTTP server
curl http://localhost:8080/__admin/stop

# Stop HTTPS server (ignore certificate)
curl -k https://localhost:8443/__admin/stop

Or call mockServer.stop() if using the Java API.

Pure JSON State

Mock state must use pure JSON objects. Avoid storing Java objects or JavaScript functions with closures - they may cause issues.

The World's Smallest Microservice

This complete CRUD microservice fits in under 300 characters - demonstrating the power of Karate mocks:

Gherkin
Feature:

Background:
* def id = 0
* def m = {}

Scenario: methodIs('post')
* def c = request
* def id = ~~(id + 1)
* c.id = id
* m[id + ''] = c
* def response = c

Scenario: pathMatches('/cats/{id}')
* def response = m[pathParams.id]

Scenario:
* def response = $m.*

This implements POST (create), GET by ID, and GET all for a /cats resource. The ~~ operator converts to integer, and $m.* returns all values from the map.

Next Steps