Q27 of 40 · Karate
How do you handle test data setup and teardown across Karate scenarios?
Short answer
Short answer: Call a create-resource.feature helper in Background (or at the top of each scenario) to POST test data and capture IDs. Clean up with a delete feature called from a Java @AfterEach hook or at the scenario end with * call read('classpath:helpers/delete-user.feature') { id: userId }. Use UUID-prefixed names for parallel safety.
Detail
Karate scenarios are stateless feature-file runs — teardown must be explicit.
Pattern 1 — inline setup/teardown (small tests):
Scenario: Update user name
# Setup
* def user = call read('classpath:helpers/create-user.feature')
{ email: 'u-' + karate.uuid() + '@test.com' }
# Test
Given path '/users/' + user.id
And request { name: 'Updated Name' }
When method PUT
Then status 200
# Teardown
* call read('classpath:helpers/delete-user.feature') { id: user.id }
Pattern 2 — Java @AfterEach hook (suite-level cleanup):
@AfterEach
void cleanup() {
if (createdUserId != null) {
given(adminSpec).when().delete("/users/" + createdUserId)
.then().statusCode(anyOf(is(204), is(404)));
}
}
Pattern 3 — tag-based cleanup run: after the test suite, run a dedicated cleanup feature that deletes all resources matching a UUID prefix used during the run. This is useful when individual teardown fails intermittently.
UUID prefix: 'test-' + karate.uuid() for email, name, or any unique identifier — prevents collision in parallel runs and makes cleanup easy (delete all resources with names starting with 'test-').
// EXAMPLE
order-crud.feature
Feature: Order CRUD with setup/teardown
Background:
* url baseUrl
* header Authorization = 'Bearer ' + bearerToken
Scenario: Get order returns correct user ID
# Setup — create a user and an order
* def user = call read('classpath:helpers/create-user.feature')
{ name: 'Test User', email: 'u-' + karate.uuid() + '@test.com' }
* def order = call read('classpath:helpers/create-order.feature')
{ userId: user.id, sku: 'WIDGET-1', qty: 2 }
# Test
Given path '/orders/' + order.id
When method GET
Then status 200
And match response.userId == user.id
And match response.items[0].sku == 'WIDGET-1'
# Teardown — clean up in reverse creation order
* call read('classpath:helpers/delete-order.feature') { id: order.id }
* call read('classpath:helpers/delete-user.feature') { id: user.id }