Q6 of 40 · Karate
How do you parameterise a Karate scenario with multiple datasets?
Short answer
Short answer: Use Scenario Outline: with an Examples: table — column headers become variables available as <columnName> in steps. Karate runs the scenario once per row. For complex JSON payloads, use * def with call read and a JSON array instead — more flexible than table notation for nested objects.
Detail
Scenario Outline with Examples — best for scalar datasets:
Scenario Outline: Reject invalid emails
Given path '/users'
And request { email: '<email>', name: 'Alice' }
When method POST
Then status 400
And match response.errors.email[0] == '<errorMsg>'
Examples:
| email | errorMsg |
| | must not be blank |
| not-an-email | must be a well-formed email |
| @missing.local | must be a well-formed email |
Call read with JSON array — better for complex data:
* def cases = read('classpath:data/invalid-users.json')
* call read('classpath:helpers/create-user.feature') cases
Where invalid-users.json is [{ "email": "", "name": "Alice" }, ...]. Each element in the array drives one call to the feature.
When to prefer the JSON approach: the payload is a nested object, the column names would make the table unreadable, or the datasets are managed by non-engineers in a separate JSON file.
// EXAMPLE
validation-tests.feature
Feature: Input validation
Background:
* url 'https://api.example.com'
Scenario Outline: Reject registrations with invalid email format
Given path '/register'
And request { email: '<email>', password: 'Str0ngP@ss' }
When method POST
Then status 400
And match response.field == 'email'
And match response.message == '<message>'
Examples:
| email | message |
| | must not be blank |
| not-an-email | must be a well-formed email |
| user@ | must be a well-formed email |
| @example.com | must be a well-formed email |
# Report shows 4 separate scenario runs, one per row