Q27 of 40 · Karate

How do you handle test data setup and teardown across Karate scenarios?

KarateSeniorkaratetest-datasetup-teardownisolationparallel-safety

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 }

// WHAT INTERVIEWERS LOOK FOR

Explicit setup and teardown, UUID prefix for parallel safety, inline teardown with the call pattern, and the fallback of Java @AfterEach for reliable cleanup when the Karate scenario teardown may fail.

// COMMON PITFALL

No teardown at all, relying on the next test run to clean up or the test environment being wiped periodically. This causes accumulating dirty state, eventual 409 conflicts, and tests that fail on Monday morning after a weekend of no cleanup.