EXTENSIONS
Test Doubles and Mocking
Create standalone mock servers with stateful behavior for API testing, consumer-driven contracts, and microservice development without external dependencies.
Karate v2 features a completely rewritten mock server with the new JS engine and a Netty-based HTTP server for improved performance. All v1 mock APIs are preserved. New: JavaScript file handlers, built-in CORS support, and non-blocking response delays.
On this page:
- Request matching - Route requests with pathMatches(), methodIs()
- Request variables - Access request, requestHeaders, pathParams
- Response building - Set response, responseStatus, responseDelay
- Starting mocks - karate.start() and MockServer API
- Stateful mocks - Maintain state across requests
- Proxy mode - Forward requests with karate.proceed()
- Server lifecycle - Background vs Scenario execution
- Standalone server - Command-line options
Request Matching
Matching Predicates
Karate provides helper functions for request matching:
| Function | Description | Example |
|---|---|---|
pathMatches() | Match request paths with path parameters | pathMatches('/users/{id}') |
methodIs() | Check HTTP method (recommended) | methodIs('post') |
paramExists() | Check if query parameter exists | paramExists('name') |
paramValue() | Get single query parameter value | paramValue('limit') |
typeContains() | Match Content-Type header | typeContains('xml') |
acceptContains() | Match Accept header | acceptContains('json') |
headerContains() | Check header contents | headerContains('Authorization', 'Bearer') |
bodyPath() | Query request body using JsonPath/XPath | bodyPath('$.username') |
Request Variables
Available variables for inspecting incoming requests:
| Variable | Description | Example Value |
|---|---|---|
request | Request body (parsed as JSON/XML, or string) | { "name": "John" } |
requestBytes | Raw request body as bytes (for binary content) | [byte array] |
requestMethod | HTTP method in uppercase | GET, POST |
requestPath | Path without query string | /users/1 |
requestUri | Path with query string | /users?page=2 |
requestUrlBase | Protocol, host, and port | http://localhost:8080 |
requestHeaders | All headers (Map of Lists) | { 'Content-Type': ['application/json'] } |
requestParams | Query parameters (Map of Lists) | { 'page': ['2'] } |
requestParts | Multipart parts for file uploads | { 'file': [{ filename: '...' }] } |
pathParams | Path parameters from URL pattern | { 'id': '1' } |
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:
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:
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:
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:
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:
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:
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:
| Variable | Description | Default |
|---|---|---|
response | Response body (JSON, XML, string, or bytes) | '' |
responseStatus | HTTP status code | 200 |
responseHeaders | Response headers as JSON object | {} |
responseDelay | Delay in milliseconds before responding | 0 |
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. In Karate v2, delays use Netty's non-blocking scheduler — they don't consume threads:
Feature: Delayed responses
Scenario: pathMatches('/slow-api')
* def responseDelay = 2000
* def response = { data: 'delayed response' }
For random delays across all scenarios, use configure afterScenario:
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' }
Per-Request Setup with beforeScenario
Mock Background only runs once at server init, so use configure beforeScenario for logic that must run per incoming request (e.g. request-scoped counters, request logging, dynamic auth checks):
Feature: Per-request counter
Background:
* def hits = { count: 0 }
* configure beforeScenario = function(){ hits.count++ }
Scenario: pathMatches('/status')
* def response = { hits: hits.count }
Both beforeScenario and afterScenario surface hook failures as an HTTP 500 response with the error in the body — wrap the hook body in try/catch if you want to suppress errors. See Hooks and Lifecycle for broader lifecycle coverage.
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:
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:
Feature: Mock with options
Background:
* def mock = karate.start({ mock: 'user-mock.feature', port: 8090 })
* url 'http://localhost:8090'
| Option | Description |
|---|---|
mock | Path to mock feature file (required) |
port | Fixed port number (default: random) |
ssl | Enable HTTPS (default: false) |
cert | SSL certificate path |
key | SSL private key path |
Java API
Embed mocks in JUnit tests using MockServer:
import io.karatelabs.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
}
}
Karate v1 API (still works via compatibility shim)
import com.intuit.karate.core.MockServer;
// Same API — delegates to v2 internally
MockServer server = MockServer
.feature("classpath:mock.feature")
.arg("key", "value")
.http(0).build();
CLI Mock Server
Start a mock server from the command line:
karate mock -m api.feature -p 8080
karate mock -m users.feature -m orders.feature -p 8080 # multiple features
karate mock -m api.feature -p 8443 --ssl # HTTPS
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:
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:
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:
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:
| Phase | Normal Karate | Mock Server |
|---|---|---|
| Background | Runs before each Scenario | Runs once on startup |
| Scenario | Runs sequentially | Evaluated per incoming request |
Request Matching
For each incoming HTTP request:
- Scenario expressions are evaluated in order from top to bottom
- The first scenario whose expression evaluates to
trueis executed - If no scenario matches, no response is returned (connection timeout)
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:
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:
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:
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:
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:
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 using the karate CLI via the mock subcommand:
# Basic server
karate mock -m mock.feature -p 8080
# Multiple mock files (evaluated in order)
karate mock -m users.feature -m orders.feature -p 8080
# With SSL (auto-generated certificate)
karate mock -m mock.feature -p 8443 -s
# Hot reload during development
karate mock -m mock.feature -p 8080 -W
# With environment
karate mock -m mock.feature -p 8080 -e staging
Command-Line Options
| Option | Description |
|---|---|
-m | Mock feature file (can specify multiple) |
-p | Port number |
-s | Enable SSL (auto-generates certificate if none provided) |
-c | SSL certificate file (PEM format) |
-k | SSL private key file (PEM format) |
-e | Set karate.env value |
-W | Watch mode - hot reload on file changes |
--keep-original-headers | Preserve 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.
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:
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.
Matcher Functions Reference
Each matcher function is designed to be used in Scenario expressions. You can combine multiple matchers with && and || operators for precise request matching.
pathMatches(pattern)
Match URL paths using placeholders. Extracted values are available in the pathParams map:
Scenario: pathMatches('/users/{id}')
# /users/42 -> pathParams.id == '42'
* def response = { id: pathParams.id }
Scenario: pathMatches('/v1/cats/{catId}/toys/{toyId}')
# /v1/cats/3/toys/7 -> pathParams.catId == '3', pathParams.toyId == '7'
* def response = { cat: pathParams.catId, toy: pathParams.toyId }
Path parameters are always strings. Use ~~pathParams.id to convert to an integer.
methodIs(method)
Case-insensitive HTTP method check. Always preferred over comparing requestMethod directly:
Scenario: pathMatches('/users') && methodIs('get')
* def response = []
Scenario: pathMatches('/users') && methodIs('post')
* def response = request
* def responseStatus = 201
typeContains(str)
Check if the Content-Type header contains the given substring:
Scenario: pathMatches('/data') && typeContains('xml')
# Matches application/xml, text/xml, application/soap+xml, etc.
* def response = '<result>OK</result>'
* def responseHeaders = { 'Content-Type': 'application/xml' }
Scenario: pathMatches('/data') && typeContains('json')
# Matches application/json, application/ld+json, etc.
* def response = { result: 'OK' }
acceptContains(str)
Check if the Accept header contains the given substring. Useful for content negotiation:
Scenario: pathMatches('/data') && acceptContains('xml')
* def responseHeaders = { 'Content-Type': 'application/xml' }
* def response = '<data>value</data>'
Scenario: pathMatches('/data') && acceptContains('json')
* def response = { data: 'value' }
headerContains(name, value)
Check if any value of a named header contains the given substring:
Scenario: pathMatches('/protected') && headerContains('Authorization', 'Bearer')
* def response = { status: 'authorized' }
Scenario: pathMatches('/protected')
* def responseStatus = 401
* def response = { error: 'Missing or invalid authorization' }
paramValue(name)
Get the value of a query string or form parameter. Returns null if the parameter does not exist:
Scenario: pathMatches('/search') && paramValue('q')
* def query = paramValue('q')
* def limit = paramValue('limit') || '10'
* def response = { query: query, limit: ~~limit, results: [] }
paramExists(name)
Check whether a query string or form parameter exists, regardless of its value:
Scenario: pathMatches('/items') && paramExists('verbose')
* def response = { items: [], debug: true, timestamp: new Date().toISOString() }
Scenario: pathMatches('/items')
* def response = { items: [] }
bodyPath(expression)
Extract a value from the request body using JsonPath or XPath. Paths starting with / are treated as XPath, otherwise JsonPath:
Scenario: pathMatches('/process') && bodyPath('$.action') == 'submit'
* def name = bodyPath('$.user.name')
* def response = { accepted: true, name: name }
Scenario: pathMatches('/soap') && bodyPath('/Envelope/Body/Action') == 'GetUser'
* def response = '<User><Name>John</Name></User>'
Request and Response Variables
Request Variables
The following variables are automatically set for each incoming request and are available in all mock Scenario blocks:
| Variable | Type | Description |
|---|---|---|
request | Object | Parsed request body — JSON becomes a JS object, XML becomes an XML object, otherwise a string |
requestBytes | byte[] | Raw request body as a byte array, useful for binary content |
requestPath | String | URL path without the query string, e.g. /users/1 |
requestUri | String | Full path including the query string, e.g. /users?page=2 |
requestUrlBase | String | Protocol, host, and port, e.g. http://localhost:8080 |
requestMethod | String | HTTP method in uppercase, e.g. GET, POST |
requestHeaders | Map | All headers as a map where each value is a list of strings |
requestCookies | Map | Request cookies as a map of { name, value } objects |
requestParams | Map | Query string or form parameters as a map of string lists |
requestParts | Map | Multipart parts for file uploads, keyed by part name |
pathParams | Map | Path parameters extracted by pathMatches(), e.g. { id: '42' } |
Response Variables
Set these variables within a Scenario to control what the mock server returns:
| Variable | Type | Default | Description |
|---|---|---|---|
response | any | null | Response body — auto-serialized to JSON, XML, or plain text |
responseStatus | int | 200 | HTTP status code |
responseHeaders | Map | {} | Additional response headers, merged with global headers |
responseDelay | int | 0 | Delay in milliseconds before sending the response (non-blocking in v2) |
Use configure responseHeaders in the Background to set headers for all responses. Setting responseHeaders in a Scenario overrides the global values for that specific response.
Stateful Mocks
Variables defined in the Background section execute once on server startup and persist across all requests. This makes it straightforward to build mocks that maintain state, such as an in-memory datastore.
In-Memory CRUD Example
The following mock implements a complete REST resource with create, read, update, and delete operations backed by a simple JavaScript map:
Feature: Task manager mock
Background:
* def nextId = 1
* def tasks = {}
* configure responseHeaders = { 'Content-Type': 'application/json' }
Scenario: pathMatches('/tasks') && methodIs('get')
* def response = karate.valuesOf(tasks)
Scenario: pathMatches('/tasks') && methodIs('post')
* def task = request
* task.id = nextId
* task.status = task.status || 'pending'
* tasks[nextId + ''] = task
* nextId = nextId + 1
* def response = task
* def responseStatus = 201
Scenario: pathMatches('/tasks/{id}') && methodIs('get')
* def task = tasks[pathParams.id]
* def response = task || { error: 'Task not found' }
* def responseStatus = task ? 200 : 404
Scenario: pathMatches('/tasks/{id}') && methodIs('put')
* def existing = tasks[pathParams.id]
* if (!existing) responseStatus = 404
* if (!existing) response = { error: 'Task not found' }
* if (existing) tasks[pathParams.id] = karate.merge(existing, request)
* if (existing) response = tasks[pathParams.id]
Scenario: pathMatches('/tasks/{id}') && methodIs('delete')
* def existing = tasks[pathParams.id]
* if (existing) delete tasks[pathParams.id]
* def responseStatus = existing ? 204 : 404
Scenario:
* def responseStatus = 404
* def response = { error: 'Not found' }
Because the Background runs only once, nextId and tasks retain their values across every request. Creating a task increments the ID counter permanently, and subsequent GET requests see all previously created tasks.
The mock handler synchronizes request processing, so concurrent access to shared state is safe. However, you should keep state as pure JSON objects. Avoid storing Java objects or JavaScript closures in mock state.
Proxy Mode
Karate mocks can act as HTTP proxies using karate.proceed(). This enables a powerful pattern sometimes called "AOP for web services" — you can intercept, inspect, modify, or selectively stub requests while forwarding the rest to a real backend.
Forward to a Specific Target
Pass a URL to karate.proceed() to forward the request to that host. The request path, method, headers, and body are all forwarded:
Scenario: pathMatches('/api/{path}')
* karate.proceed('https://api.example.com')
# response, responseStatus, and responseHeaders are now set from the backend
Forward to the Original Host
Call karate.proceed() with no arguments to forward using the host from the original request. This is useful when the mock is configured as a true HTTP proxy:
Scenario: pathMatches('/api/{path}')
* karate.proceed()
Selective Interception
The real power of proxy mode is combining stubs with forwarding. More specific Scenarios placed before the forwarding Scenario intercept particular requests while everything else passes through:
Feature: Selective proxy
Background:
* def backendUrl = 'https://api.example.com'
Scenario: pathMatches('/api/users/0') && methodIs('get')
# Stub: always return a test user for ID 0
* def response = { id: 0, name: 'Test User', role: 'admin' }
Scenario: pathMatches('/api/health')
# Stub: always healthy, even if real backend is down
* def response = { status: 'UP' }
Scenario: pathMatches('/api/{path}')
# Forward everything else to real backend
* karate.proceed(backendUrl)
# Optionally modify the proxied response
* response.proxied = true
Modifying Proxied Responses
After karate.proceed() returns, the response, responseStatus, and responseHeaders variables contain the backend's response. You can modify any of these before the mock returns the response to the client:
Scenario: pathMatches('/api/{path}')
* karate.proceed('https://api.example.com')
* response.timestamp = new Date().toISOString()
* response.source = 'proxy'
JavaScript Mock Handlers
As an alternative to feature files, you can write mock handlers in plain JavaScript. A JS file is evaluated as a block for each incoming request, with three objects available: request, response, and session.
// session persists across requests (like Background variables in feature files)
session.items = session.items || {};
session.counter = session.counter || 1;
if (request.pathMatches('/items') && request.post) {
var id = '' + session.counter++;
var item = request.body;
item.id = id;
session.items[id] = item;
response.status = 201;
response.body = item;
} else if (request.pathMatches('/items/{id}') && request.get) {
var item = session.items[request.pathParams.id];
if (item) {
response.body = item;
} else {
response.status = 404;
response.body = { error: 'Not found' };
}
} else if (request.pathMatches('/items') && request.get) {
response.body = Object.values(session.items);
} else {
response.status = 404;
response.body = { error: 'Unknown path' };
}
Available Objects in JS Handlers
| Object | Key Properties |
|---|---|
request | body, pathMatches(pattern), pathParams, param(name), get, post, put, delete (boolean method checks), proceed(url) |
response | status, body, headers |
session | Persistent key-value store across requests, equivalent to Background variables |
JS handlers are useful when you need tighter integration with Java code or want to avoid Gherkin syntax overhead. For advanced JS handler patterns, see MOCKS.md.
Proxy Mode in JS Handlers
request.proceed(url) forwards the current request to a backend and returns the response — the JS-handler equivalent of karate.proceed(). Omit the URL to target the request's Host header.
// Forward and return backend response as-is
var r = request.proceed('http://real-backend:8080');
response.status = r.status;
response.body = r.body;
// Modify response before returning
var r = request.proceed('http://real-backend:8080');
response.body = { original: r.body, modifiedAt: new Date().toISOString() };
HTML Templating
Karate includes a built-in templating engine based on Thymeleaf syntax but powered by JavaScript expressions. It supports server-rendered HTML with features like th:text, th:if, th:each, session management, and HTMX integration for dynamic partial page updates. This makes it possible to build lightweight web applications or admin interfaces directly alongside your mock servers.
For full templating documentation, see TEMPLATING.md.
Mock Server CLI
The command-line interface provides a quick way to start mock servers without writing any Java or build configuration.
Basic Usage
# Start a mock on port 8080
karate mock -m users.feature -p 8080
# Combine multiple mock feature files (scenarios evaluated in order)
karate mock -m users.feature -m orders.feature -p 8080
Watch Mode
Use -W to enable hot-reload. The server automatically picks up changes when you edit the feature file, so you can iterate without restarting:
karate mock -m api.feature -p 8080 -W
SSL
Enable HTTPS with --ssl. Karate auto-generates a self-signed certificate if you do not provide one:
# Auto-generated certificate
karate mock -m api.feature -p 8443 --ssl
# Custom certificate and key
karate mock -m api.feature -p 8443 --ssl --cert cert.pem --key key.pem
CLI Options Reference
| Option | Description |
|---|---|
-m, --mock <file> | Mock feature file (repeatable for multiple files) |
-p, --port <port> | Port number (default: 0 for random available port) |
-s, --ssl | Enable HTTPS with auto-generated certificate |
-c, --cert <file> | SSL certificate file in PEM format |
-k, --key <file> | SSL private key file in PEM format |
-e | Set the karate.env value |
-W, --watch | Watch mode — hot-reload on file changes |
--path-prefix <prefix> | URL path prefix to strip from incoming requests |
Next Steps
- Load test your APIs: Performance Testing
- Extend Karate functionality: Actions and Hooks
- Configure parallel test execution: Parallel Execution
- Build reusable test components: Calling Features
- Debug mock servers: Debugging and Troubleshooting