REUSABILITY
Dynamic Scenarios
What You'll Learn
- Create dynamic Scenario Outlines with runtime data sources
- Use @setup tag for data preparation and scenario generation
- Implement conditional scenario execution based on environment
- Generate test scenarios from API responses or databases
- Filter and transform data for targeted test execution
- Combine multiple data sources for complex test scenarios
Overview
Dynamic scenarios allow you to generate and execute test scenarios based on runtime conditions, external data sources, or API responses. This powerful capability enables adaptive testing that responds to changing environments, data-driven test generation, and complex test orchestration patterns.
Dynamic Scenario Outline
Single Cell Examples
When an Examples
table has exactly one row and one column, Karate treats it as a dynamic data source:
Feature: Dynamic data-driven testing
Scenario Outline: Process item: ${name}
Given url apiUrl
And path 'items', id
And request { name: '#(name)', type: '#(type)' }
When method post
Then status 201
# Single cell triggers dynamic mode
Examples:
| read('classpath:test-data/items.json') |
```gherkin
### Runtime Data Generation
Generate test data at runtime using JavaScript functions:
```gherkin
Background:
* def generateData =
"""
function() {
var result = [];
for (var i = 1; i <= 10; i++) {
result.push({
id: i,
name: 'Item-' + i,
value: Math.floor(Math.random() * 100)
});
}
return result;
}
"""
Scenario Outline: Test generated item: ${name}
* print 'Testing item:', name, 'with value:', value
* match value == '#number'
* match value >= 0 && value < 100
Examples:
| generateData() |
```gherkin
## The @setup Tag
### Basic Setup Scenario
The `@setup` tag creates a special scenario that runs before the feature and prepares data:
```gherkin
Feature: Testing with setup data
@setup
Scenario: Prepare test data
* url apiUrl
* path '/test-data/generate'
* method get
* status 200
* def testItems = response.items
* def testConfig = response.config
Scenario Outline: Process ${name} with config
* print 'Config:', karate.setup().testConfig
* url apiUrl
* path 'items', id
* header X-Config = karate.setup().testConfig.token
* method get
* status 200
Examples:
| karate.setup().testItems |
```gherkin
### Setup with API Calls
Use `@setup` to fetch data from APIs before test execution:
```gherkin
@setup
Scenario: Get active users from API
* url userServiceUrl
* path '/users/active'
* method get
* status 200
* def activeUsers = response.users
# Filter for specific test scenarios
* def testUsers = activeUsers.filter(u => u.role == 'tester')
Scenario Outline: Validate user ${username}
* url apiUrl
* path '/validate', userId
* method post
* status 200
* match response.valid == true
Examples:
| karate.setup().testUsers |
```gherkin
### Named Setup Scenarios
Use named setup scenarios for multiple data preparations:
```gherkin
@setup=users
Scenario: Setup user data
* def userData = read('classpath:test-data/users.json')
@setup=products
Scenario: Setup product data
* def productData = read('classpath:test-data/products.json')
Scenario Outline: Test user ${name}
Examples:
| karate.setup('users').userData |
Scenario Outline: Test product ${productName}
Examples:
| karate.setup('products').productData |
```gherkin
## Setup Once Pattern
### Efficient Data Loading
Use `karate.setupOnce()` to run setup only once per feature:
```gherkin
@setup
Scenario: Expensive setup operation
* print 'This runs only once'
* url dataServiceUrl
* path '/generate-test-data'
* method post
* request { count: 100 }
* status 200
* def testData = response.data
Scenario Outline: First test batch: ${id}
* print 'Testing:', id
Examples:
| karate.setupOnce().testData[0:50] |
Scenario Outline: Second test batch: ${id}
* print 'Testing:', id
Examples:
| karate.setupOnce().testData[50:100] |
```gherkin
## Conditional Scenarios
### Environment-Based Execution
Generate scenarios based on environment:
```gherkin
@setup
Scenario: Environment-specific setup
* def env = karate.env
* def scenarios = []
* if (env == 'prod') scenarios = read('prod-scenarios.json')
* if (env == 'staging') scenarios = read('staging-scenarios.json')
* if (env == 'dev') scenarios = read('dev-scenarios.json')
# Add environment-specific headers
* def enrichedScenarios = scenarios.map(s => {
s.headers = { 'X-Environment': env };
return s;
})
Scenario Outline: ${testName}
* url apiUrl
* path endpoint
* headers headers
* method method
* status expectedStatus
Examples:
| karate.setup().enrichedScenarios |
```gherkin
### Feature Toggle Testing
Test different feature combinations:
```gherkin
@setup
Scenario: Get feature flags
* url configServiceUrl
* path '/features/active'
* method get
* status 200
* def activeFeatures = response.features
# Create test scenarios for each active feature
* def featureTests = activeFeatures.map(f => ({
featureName: f.name,
endpoint: f.testEndpoint,
expectedBehavior: f.expectedBehavior
}))
Scenario Outline: Test feature: ${featureName}
* url apiUrl
* path endpoint
* method get
* status 200
* match response contains expectedBehavior
Examples:
| karate.setup().featureTests |
```gherkin
## Data Filtering and Transformation
### Filtered Test Execution
Filter data for specific test scenarios:
```gherkin
@setup
Scenario: Setup with filtering
* def allData = read('classpath:large-dataset.json')
# Filter for specific test criteria
* def criticalTests = allData.filter(d => d.priority == 'critical')
* def edgeCases = allData.filter(d => d.type == 'edge-case')
* def happyPath = allData.filter(d => d.type == 'happy-path')
Scenario Outline: Critical test: ${name}
* print 'Running critical test:', name
# Test implementation
Examples:
| karate.setup().criticalTests |
```gherkin
### Data Transformation
Transform data before test execution:
```gherkin
@setup
Scenario: Transform test data
* def rawData = read('classpath:raw-test-data.json')
# Enrich data with additional fields
* def enrichedData = rawData.map(item => {
item.timestamp = new Date().toISOString();
item.testId = java.util.UUID.randomUUID().toString();
item.environment = karate.env;
return item;
})
Scenario Outline: Test ${testId}
* print 'Running test at:', timestamp
* url apiUrl
* path '/test', testId
* request payload
* method post
* status 201
Examples:
| karate.setup().enrichedData |
```gherkin
## Complex Data Sources
### Database-Driven Scenarios
Generate scenarios from database queries:
```gherkin
@setup
Scenario: Load from database
* def DbUtils = Java.type('com.example.DbUtils')
* def connection = DbUtils.getConnection()
# Query test scenarios from database
* def testCases = DbUtils.query(connection,
"SELECT * FROM test_cases WHERE status = 'pending' AND priority = 'high'")
# Transform database results
* def scenarios = testCases.map(tc => ({
id: tc.test_id,
name: tc.test_name,
input: JSON.parse(tc.input_json),
expected: JSON.parse(tc.expected_json)
}))
* eval DbUtils.closeConnection(connection)
Scenario Outline: Database test: ${name}
* url apiUrl
* path '/test', id
* request input
* method post
* status 200
* match response == expected
Examples:
| karate.setup().scenarios |
```gherkin
### Multi-Source Aggregation
Combine data from multiple sources:
```gherkin
@setup
Scenario: Aggregate multiple data sources
# Load from file
* def fileData = read('classpath:test-data.json')
# Call API
* url dataServiceUrl
* path '/current-data'
* method get
* status 200
* def apiData = response.data
# Generate dynamic data
* def dynamicData = []
* eval for(var i = 0; i < 5; i++) dynamicData.push({ id: 'gen-' + i })
# Combine all sources
* def allTestData = fileData.concat(apiData).concat(dynamicData)
Scenario Outline: Combined test: ${id}
* print 'Testing:', id
# Test implementation
Examples:
| karate.setup().allTestData |
```gherkin
## Advanced Patterns
### Recursive Test Generation
Generate tests that create more tests:
```gherkin
@setup
Scenario: Recursive test setup
* def generateTestTree =
"""
function(depth, breadth) {
var tests = [];
for (var i = 0; i < breadth; i++) {
var test = {
id: 'test-' + depth + '-' + i,
depth: depth
};
if (depth > 0) {
test.children = generateTestTree(depth - 1, breadth);
}
tests.push(test);
}
return tests;
}
"""
* def testTree = generateTestTree(3, 2)
Scenario Outline: Hierarchical test: ${id}
* print 'Testing at depth:', depth
# Test implementation
Examples:
| karate.setup().testTree |
```gherkin
### Conditional Data Loading
Load different data based on conditions:
```gherkin
@setup
Scenario: Conditional data loading
* def loadTestData =
"""
function() {
var hour = new Date().getHours();
var data;
if (hour < 12) {
// Morning tests
data = karate.read('classpath:morning-tests.json');
} else if (hour < 18) {
// Afternoon tests
data = karate.read('classpath:afternoon-tests.json');
} else {
// Evening tests
data = karate.read('classpath:evening-tests.json');
}
return data;
}
"""
* def testData = loadTestData()
Scenario Outline: Time-based test: ${name}
* print 'Running time-specific test:', name
Examples:
| karate.setup().testData |
```gherkin
## Best Practices
### Setup Organization
```gherkin
# ✅ Good: Clear, focused setup scenarios
@setup
Scenario: Prepare user test data
* def users = read('users.json')
* def validUsers = users.filter(u => u.valid)
# ❌ Avoid: Overly complex setup
@setup
Scenario: Do everything
# Too much logic in one setup
```gherkin
### Performance Considerations
```gherkin
# ✅ Good: Use setupOnce for expensive operations
@setup
Scenario: Expensive API call
* print 'This expensive call happens once'
* def data = karate.call('expensive-operation.feature')
Scenario Outline: Test ${id}
Examples:
| karate.setupOnce().data |
```gherkin
### Error Handling
```gherkin
# ✅ Good: Handle setup failures gracefully
@setup
Scenario: Safe setup
* def data = []
* try
* data = read('test-data.json')
* catch (e)
* print 'Failed to load data:', e
* data = [{ id: 'default', name: 'fallback' }]
```gherkin
## Troubleshooting
### Common Issues
```gherkin
# Issue: Setup not running
# Solution: Ensure @setup tag is present
@setup # Required tag
Scenario: Setup scenario
# Issue: Data not available
# Solution: Use karate.setup() to access
Examples:
| karate.setup().myData | # Correct
| myData | # Won't work
# Issue: Setup running multiple times
# Solution: Use setupOnce()
Examples:
| karate.setupOnce().data | # Runs once
```gherkin
## Next Steps
- Explore [Advanced Configuration](/docs/advanced/configuration) for environment setup
- Learn about [Hooks and Lifecycle](/docs/advanced/hooks) for test orchestration
- Understand [Parallel Execution](/docs/running-tests/parallel-execution) with dynamic scenarios