Stop copying Karate API tests: use Scenario Outline with Examples
Run one Karate API scenario against many inputs using Scenario Outline and Examples tables instead of duplicating feature files.
16 Oct 2026, 06:51 UTC

The problem: one feature file per login is hard to maintain
You need to verify that a POST /login endpoint accepts several username and password combinations. Copying the same Given-When-Then block for every account makes a feature file grow linearly with your test data. Changing the request path or an assertion means editing every copy. Karate DSL’s Scenario Outline lets you write the steps once and bind each row of an Examples table to variables, so the runner executes one scenario per row.
How Scenario Outline binds data
A Scenario Outline is a template. The Examples table beneath it defines columns and rows. Inside the scenario, you reference column values with angle-bracket syntax, such as <username>. Karate substitutes the values before running each iteration. Variables from Examples are strings by default; if your API expects a number or boolean, convert it explicitly in the step or with a Karate expression.
Worked example: parameterized login tests
Create a feature file, for example src/test/resources/demo/login.feature:
Feature: Login acceptance
Background:
* url 'https://api.example.com'
Scenario Outline: Valid and invalid login attempts
Given path 'login'
And request { username: '<username>', password: '<password>' }
When method post
Then status <expectedStatus>
And match response == { token: '#present', error: '#(expectedError == null ? null : expectedError)' }
Examples:
| username | password | expectedStatus | expectedError |
| alice | secret | 200 | |
| bob | wrong | 401 | invalid credentials |
| | secret | 400 | username required |
Run the feature from the project root. With Maven, a typical command is:
mvn test -Dtest=KarateRunner -Dkarate.options="src/test/resources/demo/login.feature"
Where to run: your project directory. Permissions: read access to the feature file and write access to the target reports directory. Placeholders: replace KarateRunner with your runner class and the path with your feature location. Expected check: the runner should execute three scenarios, one per Examples row. Risk: if expectedStatus is compared as a string against an integer status code, Karate’s type handling may behave differently by release, so confirm the comparison works in your installed version.
For larger datasets, an inline Examples table becomes hard to read. Load external data instead:
Scenario Outline: Login from CSV
Given path 'login'
And request { username: '<username>', password: '<password>' }
When method post
Then status <expectedStatus>
Examples:
| read('classpath:demo/login-users.csv') |
The CSV must have headers matching the variable names. Karate reads the file and iterates over each row. This keeps secrets out of the feature file, though you should still avoid committing plain-text credentials to version control.
Trade-offs and limitations
- Inline Examples tables are fine for a handful of rows, but large tables reduce readability and make diffs noisy.
- All Examples values are strings unless you convert them. Numeric IDs or boolean flags need explicit casting before the request body or assertion uses them.
- Syntax and
read()behavior can vary between Karate releases. Confirm Scenario Outline, Examples, and external file iteration against your installed version before adding the pattern to CI. - Per-iteration failures appear in Karate’s HTML and Cucumber-compatible reports, but a single malformed row can stop the whole outline depending on configuration.
Verify before you ship
- Add a small Examples table with three rows to an existing feature file.
- Run the feature with your project’s test command.
- Open the Karate HTML report and confirm each row has its own pass or fail status with substituted variables.
- Check the Karate version in your build file and review that release’s documentation for Scenario Outline and
read()support.
If the report shows one scenario per row and the assertions match your expectations, the pattern is safe to adopt for additional endpoints. If a row fails because of type coercion, add an explicit conversion and re-run only that feature file.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.