REUSABILITY
Dynamic Scenarios
Generate test scenarios dynamically at runtime using JSON arrays, CSV files, or custom generator functions. Dynamic Scenario Outline resolves test data at execution time from files, databases, or APIs—enabling scalable data-driven testing without memory overhead.
On this page:
- JSON Data Source - Load test data from JSON files
- CSV Data Source - Use CSV for tabular test data
- @setup Tag - Generate data programmatically
- Generator Functions - Memory-efficient data generation
- Advanced Patterns - Multiple setups and external sources
Simple JSON Data Source
Load test data from a JSON file at runtime. The key pattern is a single-cell Examples table that triggers dynamic resolution:
Feature: Dynamic data from JSON
Scenario Outline: Create user: <name>
Given url 'https://jsonplaceholder.typicode.com'
And path 'users'
And request { name: '<name>', email: '<email>' }
When method post
Then status 201
# Single-cell table triggers dynamic resolution
Examples:
| read('classpath:test-data/users.json') |
Dynamic Scenario Outline requires exactly one row and one column in the Examples table. This signals Karate to resolve the data at runtime instead of using a static table.
CSV File Data Source
Use CSV files for tabular test data. Karate auto-converts CSV to JSON arrays:
Feature: CSV-driven tests
Scenario Outline: Test product: <name>
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
And request { title: '<name>', body: '<description>', userId: 1 }
When method post
Then status 201
Examples:
| read('classpath:test-data/products.csv') |
@setup Tag for Data Generation
Generate test data programmatically before running scenarios. The @setup tag marks a scenario that runs first and provides data via karate.setup():
Feature: Setup tag for dynamic data
@setup
Scenario: Generate test data
* def testPosts =
"""
[
{ title: 'First Post', body: 'Content 1', userId: 1 },
{ title: 'Second Post', body: 'Content 2', userId: 1 },
{ title: 'Third Post', body: 'Content 3', userId: 2 }
]
"""
Scenario Outline: Create post: <title>
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
And request { title: '<title>', body: '<body>', userId: <userId> }
When method post
Then status 201
And match response.title == '<title>'
Examples:
| karate.setup().testPosts |
@setupscenarios run before Background and all other scenarios- Cannot depend on Background variables
- Access setup data using
karate.setup()in the Examples table - Use
karate.setupOnce()to run setup only once per feature
Generator Functions
Simple Generator
Create large datasets without loading all data into memory. A generator function returns null to signal the end:
Feature: Memory-efficient generator
@setup
Scenario: Setup generator function
* def postGenerator =
"""
function(index) {
if (index >= 10) return null;
return {
title: 'Post ' + index,
body: 'Body content for post ' + index,
userId: (index % 3) + 1
};
}
"""
Scenario Outline: Create post: <title>
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
And request { title: '<title>', body: '<body>', userId: <userId> }
When method post
Then status 201
Examples:
| karate.setup().postGenerator |
Generator with Conditional Logic
Add computed fields or conditional values based on the index. The generator can include any logic to vary test data across iterations:
Feature: Generator with conditions
@setup
Scenario: Complex generator
* def generator =
"""
function(index) {
if (index >= 20) return null;
return {
title: 'TestPost' + index,
userId: (index % 5) + 1,
shouldSucceed: index % 4 != 0
};
}
"""
Scenario Outline: Post test <index> - <title>
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
And request { title: '<title>', userId: <userId> }
When method post
Then status 201
Examples:
| karate.setup().generator |
Advanced Patterns
Named Setup Scenarios
When a feature has multiple Scenario Outlines that need different data sources, use named setups with @setup=name syntax. Reference specific setups using karate.setup('name'):
Feature: Named setup scenarios
@setup=users
Scenario: Setup user data
* def users =
"""
[
{ id: 1, name: 'Admin' },
{ id: 2, name: 'User' }
]
"""
@setup=posts
Scenario: Setup post data
* def posts =
"""
[
{ id: 101, title: 'First' },
{ id: 102, title: 'Second' }
]
"""
Scenario Outline: Test user: <name>
Given url 'https://jsonplaceholder.typicode.com'
And path 'users', <id>
When method get
Then status 200
Examples:
| karate.setup('users').users |
Setup Once Pattern
When multiple Scenario Outlines share the same data source, use karate.setupOnce() to execute the setup scenario only once. The data is cached and reused across all outlines:
Feature: Setup once pattern
@setup
Scenario: Generate shared data
* def sharedData =
"""
[
{ postId: 1, commentBody: 'Great post!' },
{ postId: 1, commentBody: 'Thanks for sharing' }
]
"""
Scenario Outline: Add comment to post <postId>
Given url 'https://jsonplaceholder.typicode.com'
And path 'comments'
And request { postId: <postId>, body: '<commentBody>', email: 'test@test.com' }
When method post
Then status 201
Examples:
| karate.setupOnce().sharedData |
Building Test Matrix
Generate all combinations of multiple variables using nested loops. Useful for testing features across user types, environments, or configurations:
Feature: Test matrix generation
@setup
Scenario: Create test matrix
* def users = [1, 2, 3]
* def postTypes = ['text', 'image']
* def testMatrix = []
* karate.forEach(users, function(userId) { karate.forEach(postTypes, function(type) { testMatrix.push({ userId: userId, postType: type, title: type + ' post by user ' + userId }) }) })
Scenario Outline: Create <postType> post for user <userId>
Given url 'https://jsonplaceholder.typicode.com'
And path 'posts'
And request { title: '<title>', body: 'Content', userId: <userId> }
When method post
Then status 201
Examples:
| karate.setup().testMatrix |
Database-Driven Tests
Query test data directly from a database using Java interop. The setup scenario executes the query and returns rows as a JSON array for the Scenario Outline:
Feature: Database-driven tests
@setup
Scenario: Load from database
* def DbUtils = Java.type('com.mycompany.DbUtils')
* def dbConfig = { url: 'jdbc:h2:mem:test', user: 'sa' }
* def query = 'SELECT user_id, username FROM test_users WHERE active = true'
* def testUsers = DbUtils.readRows(dbConfig, query)
Scenario Outline: Test user - <username>
Given url baseUrl
And path 'user/profile'
And request { userId: <user_id> }
When method get
Then status 200
Examples:
| karate.setup().testUsers |
When to Use Dynamic Scenarios
| Use Case | Approach |
|---|---|
| Fixed, small dataset (< 20 rows) | Static Examples table |
| Runtime data (API, database, files) | Dynamic Scenario Outline |
| Large datasets (100+ test cases) | Generator functions |
| Environment-specific test generation | @setup with conditional logic |
Next Steps
- Compare data-driven approaches: Data-Driven Tests
- Reuse test logic across features: Calling Features
- Add conditional test logic: Conditional Logic
- Explore parallel test execution: Parallel Execution