49Karate Framework
What you will master here
- Why Karate exists — declarative API testing with no Java code per test
- Gherkin-on-steroids DSL
- Data-driven and chained scenarios
- Matching:
match, JSONPath, schema - Karate Gatling for performance testing
- Karate UI (web automation) and Karate Mock
- When to pick Karate vs REST Assured vs Postman vs Playwright request
49.1 What Karate is
Karate is a JVM-based, BDD-style API testing tool from Intuit. It removes Java boilerplate — tests are written in a Gherkin-derived DSL inside .feature files. No step-definition code; built-in matchers, JSON traversal, schema validation, JS expressions.
49.2 First test
Feature: users API
Background:
* url 'https://api.example.com'
* header Accept = 'application/json'
Scenario: create user
Given path '/users'
And request { name: 'Alice', email: 'alice@test.com' }
When method post
Then status 201
And match response == { id: '#string', name: 'Alice', email: 'alice@test.com', createdAt: '#string' }
And match response.id != null
* def userId = response.id
Scenario: get the user just created
Given path '/users', userId
When method get
Then status 200
And match response.email == 'alice@test.com'
49.3 The match operator (Karate's killer feature)
* def actual = { foo: 'bar', baz: 42 }
* match actual == { foo: 'bar', baz: 42 } # full equality
* match actual contains { foo: 'bar' } # partial
* match actual.baz == 42
* match actual.baz == '#number' # type
* match actual.foo == '#regex [a-z]+' # regex
* match actual contains only { foo: 'bar', baz: 42 } # exact set
# Arrays
* def list = [{ id: 1 }, { id: 2 }, { id: 3 }]
* match list[*].id == [1, 2, 3] # extract
* match each list == { id: '#number' } # every element
* match list[?(@.id == 2)] != [] # JSONPath filter
49.4 Data-driven via Examples
Scenario Outline: status code <code> for <path>
Given path '<path>'
When method get
Then status <code>
Examples:
| path | code |
| /health | 200 |
| /users/9999 | 404 |
| /admin | 403 |
49.5 Chained scenarios — calling features from features
* def created = call read('create-user.feature') { email: 'qa@test.com' }
* def userId = created.userId
Given path '/users', userId
When method get
Then status 200
49.6 Parallel runner
// JUnit 5 wrapper
public class AllTests {
@Test
public void runAll() {
Results results = Runner.path("classpath:tests")
.tags("@regression")
.parallel(8);
assertEquals(0, results.getFailCount(), results.getErrorMessages());
}
}
49.7 Karate UI + Mock
- Karate UI — Same DSL extended for browser automation (driver=chrome|firefox|playwright). Lower-level than Playwright but unifies API+UI in one feature file.
- Karate Mock — Standalone HTTP mock server defined in a feature file. Useful for service virtualisation in CI.
- Karate Gatling — Use the same feature files for load testing via Gatling.
49.8 When to pick Karate
| Pick Karate when | Pick alternative when |
|---|---|
| Team mixes engineers + non-engineers writing tests | Everyone is a developer (REST Assured or Playwright fits better) |
| You want one tool for API + perf + simple UI | You need deep UI (use Playwright) |
| Schema/structural assertions dominate | You need full type-safe TS / Java |
| You want zero step-definition code | You want code review on imperative tests |
Module 47 — Karate Q&A
What's Karate's "match" operator do?
Built-in structural comparison: equality, contains, contains only, type markers (#string, #number, #boolean), regex, JSONPath filters. Replaces a stack of Hamcrest matchers or hand-written assertions.
Karate vs REST Assured?
REST Assured is a Java DSL — you write Java test methods and chain BDD-style assertions. Karate is a feature-file DSL — no Java for the test, but you can call Java helpers when needed. Karate is more accessible to non-engineers; REST Assured fits engineer-only teams better.
How does data-driven testing work in Karate?
Scenario Outline + Examples table — same as Cucumber. Karate also supports
call-with-array for fully programmatic data-driven runs.How do you chain scenarios?
call read('other.feature') {arg: 'value'} calls another feature and returns its results as a context object. Used to share setup (create user, login) across feature files.Can Karate do load testing?
Yes — Karate Gatling reuses your feature files as Gatling scenarios. One source of truth for functional + load.
What's the parallel runner?
Built-in JUnit-driven parallel executor:
Runner.path(...).parallel(N) runs feature files across N threads. No external Maven Surefire fork config needed.Karate Complete Feature File — REST API Testing
Feature: User Management API
Background:
* url 'https://api.example.com'
* header Authorization = 'Bearer ' + karate.get('authToken')
* def baseUrl = 'https://api.example.com'
Scenario: Create user and verify response
Given path '/users'
And request { name: 'John Doe', email: 'john@example.com', role: 'admin' }
When method POST
Then status 201
And match response == { id: '#notnull', name: 'John Doe', email: 'john@example.com', createdAt: '#present' }
And match responseHeaders['Content-Type'][0] contains 'application/json'
* def userId = response.id
Scenario Outline: Get user by ID
Given path '/users/' + <userId>
When method GET
Then status <status>
And match response.name == <name>
Examples:
| userId | status | name |
| 1 | 200 | 'Alice' |
| 9999 | 404 | '#notpresent' |
Scenario: Update user with partial data (PATCH)
Given path '/users/1'
And request { name: 'Alice Updated' }
When method PATCH
Then status 200
And match response.name == 'Alice Updated'
And match response.updatedAt != response.createdAt
Scenario: Validate paginated list response
Given path '/users'
And param page = 1
And param limit = 10
When method GET
Then status 200
And match response ==
"""
{
data: '#[] #object',
total: '#number',
page: 1,
limit: 10,
hasNext: '#boolean'
}
"""
And match each response.data == { id: '#number', name: '#string', email: '#regex .+@.+' }
Karate Auth & Reusable Helpers
# auth.feature — called from other features
Feature: Authentication Helper
Scenario: Get auth token
Given url 'https://api.example.com/auth/login'
And request { username: '#(username)', password: '#(password)' }
When method POST
Then status 200
* def authToken = response.token
---
# main.feature — reuse auth
Feature: Main API Tests
Background:
* def auth = call read('classpath:auth.feature') { username: 'admin', password: 'secret' }
* def authToken = auth.authToken
* url 'https://api.example.com'
* header Authorization = 'Bearer ' + authToken
Karate JavaScript Inline Functions
Feature: Advanced Karate Patterns
Scenario: Generate dynamic test data with JS
* def uuid = function(){ return java.util.UUID.randomUUID() + '' }
* def email = function(name){ return name.toLowerCase() + '@test.com' }
* def timestamp = function(){ return new Date().toISOString() }
* def user = { id: '#(uuid())', name: 'Test User', email: '#(email("TestUser"))' }
Given path '/users'
And request user
When method POST
Then status 201
Scenario: Schema validation with match each
Given path '/products'
When method GET
Then status 200
# Every item in array must match schema
And match each response.items ==
"""
{
id: '#number',
name: '#string',
price: '#? _ > 0',
category: '#regex ^(electronics|clothing|food)$',
inStock: '#boolean',
tags: '##[] #string'
}
"""
Scenario: Test file upload
Given path '/uploads'
And multipart file file = { read: 'classpath:test-image.jpg', filename: 'image.jpg', contentType: 'image/jpeg' }
And multipart field description = 'Test upload'
When method POST
Then status 200
And match response.url contains 'https://storage.'
Karate Config & Parallel Execution
// karate-config.js
function fn() {
var env = karate.env || 'dev';
var config = {
env: env,
apiTimeout: 5000
};
if (env === 'dev') {
config.baseUrl = 'http://localhost:8080';
config.apiKey = 'dev-key-123';
} else if (env === 'staging') {
config.baseUrl = 'https://staging.api.example.com';
config.apiKey = karate.properties['staging.api.key'];
} else if (env === 'prod') {
config.baseUrl = 'https://api.example.com';
config.apiKey = karate.properties['prod.api.key'];
}
// Global setup: get auth token once for all tests
var login = karate.callSingle('classpath:auth.feature', { username: 'admin', password: 'secret' });
config.authToken = login.authToken;
return config;
}
// KarateRunner.java — parallel execution
import com.intuit.karate.junit5.Karate;
import org.junit.jupiter.api.Test;
import com.intuit.karate.Results;
import com.intuit.karate.Runner;
import static org.junit.jupiter.api.Assertions.*;
class KarateRunner {
@Test
void testParallel() {
Results results = Runner.path("classpath:features")
.outputHtmlReport(true)
.outputJunitXml(true)
.parallel(5); // 5 threads
assertEquals(0, results.getFailCount(),
results.getErrorMessages());
}
}