Test Design Guide
This guide covers the key principles and components for designing effective performance tests with the Performance Automation Framework. It consolidates information about API requests, scenarios, thread groups, and response validation.
Test Structure Overview
The Performance Automation Framework uses a hierarchical structure to organize tests:
graph TD
A[Test Plan] --> B[Thread Groups]
B --> C[Scenarios]
C --> D[Requests]
D --> E[Validation Rules]
In the YAML configuration, this hierarchy is represented as:
# Test Plan
name: API Performance Test
description: Comprehensive API performance test
# Execution configuration (thread groups)
execution:
threads: 10
iterations: 5
rampUpPeriod: 2
successThreshold: 95.0
# Scenarios
scenarios:
- name: User API Tests
variables:
endpoint: /users
# Requests
requests:
- name: Get Users
endpoint: ${baseUrl}${endpoint}
method: GET
statusCode: 200
# Validation rules
responses:
JsonPath: "$.length()>0"
API Requests
API requests are the core components of performance tests. Each request represents a single HTTP call to an API endpoint, with associated configuration such as headers, parameters, and validation rules.
Basic Request Properties
Property | Description | Required | Example |
---|---|---|---|
name |
Name of the request | Yes | "Get Users" |
endpoint |
The URL to call | Yes | "${baseUrl}/users" |
method |
HTTP method | Yes | "GET" , "POST" , "PUT" , "DELETE" |
statusCode |
Expected HTTP status code | No | 200 , 201 , 404 |
headers |
Path to headers file or inline JSON | No | "headers/common_headers.json" |
body |
Path to request body file or inline content | No | "body/create_user.json" |
params |
Path to parameters file or inline JSON | No | "params/user_list_params.txt" |
variables |
Request-specific variables | No | { "userId": 123 } |
responses |
Response validation rules | No | { "JsonPath": "$.name=John" } |
Example Requests by Method
GET Request
- name: Get Users
endpoint: ${baseUrl}/users
method: GET
statusCode: 200
headers: |
{
"Accept": "application/json"
}
params: |
{
"page": 1,
"limit": 10
}
POST Request
- name: Create User
endpoint: ${baseUrl}/users
method: POST
statusCode: 201
headers: |
{
"Content-Type": "application/json"
}
body: |
{
"name": "John Doe",
"email": "john@example.com",
"age": 30
}
PUT Request
- name: Update User
endpoint: ${baseUrl}/users/${userId}
method: PUT
statusCode: 200
headers: |
{
"Content-Type": "application/json"
}
body: |
{
"name": "John Updated",
"email": "john.updated@example.com"
}
DELETE Request
- name: Delete User
endpoint: ${baseUrl}/users/${userId}
method: DELETE
statusCode: 204
headers: |
{
"Authorization": "Bearer ${token}"
}
Resource Files
Request-related resources can be stored in external files for better organization:
src/test/resources/
├── body/ # Request bodies (JSON, XML, etc.)
├── headers/ # HTTP headers in JSON format
├── params/ # URL parameters
├── schemas/ # JSON schemas for validation
Headers File Example
{
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer ${token}"
}
Body File Example
Parameters File Example
Scenarios
Scenarios are groups of related requests that are executed together. They allow you to organize your tests into logical units, each with its own set of variables and requests.
Scenario Properties
Property | Description | Required | Example |
---|---|---|---|
name |
Name of the scenario | Yes | "User API Tests" |
variables |
Scenario-specific variables | No | { "endpoint": "/users" } |
requests |
Array of requests to execute | Yes | See examples |
Scenario Variables
Variables defined at the scenario level are available to all requests within that scenario but not to requests in other scenarios:
scenarios:
- name: User API Tests
variables:
endpoint: /users
resourceType: user
requests:
# These requests can access the 'endpoint' and 'resourceType' variables
- name: Post API Tests
variables:
endpoint: /posts
resourceType: post
requests:
# These requests can access the 'endpoint' and 'resourceType' variables,
# but with different values than in the User API Tests scenario
When to Use Multiple Scenarios vs Multiple Requests
Use Multiple Scenarios When:
- You want to test different API areas independently
- You need different variable sets for different groups of requests
- You want to represent different user workflows
- You want to isolate the performance metrics of different API areas
Use Multiple Requests Within a Scenario When:
- The requests are closely related and part of the same workflow
- The requests share common variables
- The requests need to be executed in a specific sequence
- You want to measure the combined performance of a sequence of API calls
Example Scenario
scenarios:
- name: User Management
variables:
baseEndpoint: /users
requests:
- name: List Users
endpoint: ${baseUrl}${baseEndpoint}
method: GET
statusCode: 200
- name: Get User Details
endpoint: ${baseUrl}${baseEndpoint}/1
method: GET
statusCode: 200
- name: Create User
endpoint: ${baseUrl}${baseEndpoint}
method: POST
statusCode: 201
headers: headers/content_type_json.json
body: body/create_user.json
Thread Groups
Thread groups represent virtual users that execute test scenarios. Each thread group consists of one or more threads (virtual users) that execute a sequence of HTTP requests defined in a scenario.
Thread Group Configuration
Thread groups are automatically created from scenarios defined in the YAML configuration. The thread group properties are derived from the execution configuration:
execution:
threads: 10 # Number of threads (virtual users)
iterations: 5 # Number of iterations per thread
rampUpPeriod: 2 # Time in seconds to start all threads
successThreshold: 95.0 # Minimum success rate required
Thread Group Properties
Number of Threads
The threads
parameter specifies how many concurrent users will execute the scenario. Each thread represents a single user and executes the scenario independently.
Iterations
The iterations
parameter determines how many times each thread will execute the scenario. Each iteration executes all the requests in the scenario in sequence.
Ramp-Up Period
The rampUpPeriod
parameter specifies the time in seconds to start all threads. The threads are started evenly over the ramp-up period.
gantt
title Thread Start Times (10 threads, 5 second ramp-up)
dateFormat s
axisFormat %S
Thread 1 : milestone, m1, 0, 0
Thread 2 : milestone, m2, 0.5, 0.5
Thread 3 : milestone, m3, 1, 1
Thread 4 : milestone, m4, 1.5, 1.5
Thread 5 : milestone, m5, 2, 2
Thread 6 : milestone, m6, 2.5, 2.5
Thread 7 : milestone, m7, 3, 3
Thread 8 : milestone, m8, 3.5, 3.5
Thread 9 : milestone, m9, 4, 4
Thread 10 : milestone, m10, 4.5, 4.5
Load Profiles
The combination of thread count, iterations, and ramp-up period defines the load profile of the test:
Constant Load
All threads start immediately and execute for the duration of the test.
Gradual Ramp-Up
Threads are started gradually over the ramp-up period, then maintain the full thread count until the test completes.
Advanced Thread Group Configuration
Limited Duration Tests
To run a test for a fixed duration regardless of the number of iterations:
execution:
threads: 10
iterations: -1 # -1 = infinite iterations
rampUpPeriod: 5
durationSeconds: 300 # Run for 5 minutes
Think Time
To simulate realistic user behavior with pauses between requests:
execution:
threads: 10
iterations: 5
rampUpPeriod: 2
thinkTimeMs: 500 # 500ms delay between requests
Response Validation
The framework provides multiple mechanisms for validating API responses, ensuring that your performance tests also verify functional correctness.
HTTP Status Code Validation
The framework automatically validates that the response has the expected status code specified in the statusCode
property:
requests:
- name: Get User
endpoint: ${baseUrl}/users/1
method: GET
statusCode: 200 # Expected status code is 200 OK
Response Content Validation
The responses
property allows you to specify additional validation rules for the response:
JSON Path Validation
Multiple JSON Path validations:
Response Contains Validation
Multiple content validations:
Response Size Validation
XPath Validation (for SOAP/XML)
xpath:
- expression: "//m:Temperature"
expected: "72"
namespaces:
m: "http://www.example.org/weather"
soap: "http://schemas.xmlsoap.org/soap/envelope/"
Success Threshold
The framework allows you to specify a success threshold in the execution configuration. If the percentage of successful requests falls below this threshold, the test will be considered a failure:
execution:
threads: 10
iterations: 5
rampUpPeriod: 2
successThreshold: 95.0 # Test fails if success rate is below 95%
Complete Test Design Example
Here's a comprehensive example that demonstrates the various aspects of test design:
name: E-commerce API Performance Test
description: Tests the performance of core e-commerce APIs
variables:
baseUrl: https://api.example.com
apiVersion: v1
execution:
threads: 20
iterations: 10
rampUpPeriod: 5
successThreshold: 95.0
thinkTimeMs: 500
variables:
sessionId: "session-${__randomString(8)}"
scenarios:
- name: Product Browsing
variables:
productsEndpoint: /products
categoriesEndpoint: /categories
requests:
- name: List Categories
endpoint: ${baseUrl}/${apiVersion}${categoriesEndpoint}
method: GET
statusCode: 200
responses:
JsonPath: "$.length()>0"
- name: List Products
endpoint: ${baseUrl}/${apiVersion}${productsEndpoint}
method: GET
params: |
{
"limit": 20,
"page": 1
}
statusCode: 200
responses:
JsonPath: "$.products.length()>0"
- name: Get Product Details
endpoint: ${baseUrl}/${apiVersion}${productsEndpoint}/12345
method: GET
statusCode: 200
responses:
JsonPath:
- "$.id=12345"
- "$.name!=null"
- "$.price>0"
- name: Shopping Cart
variables:
cartEndpoint: /cart
checkout: /checkout
requests:
- name: Add to Cart
endpoint: ${baseUrl}/${apiVersion}${cartEndpoint}
method: POST
headers: |
{
"Content-Type": "application/json",
"X-Session-ID": "${sessionId}"
}
body: |
{
"productId": 12345,
"quantity": 1
}
statusCode: 201
- name: View Cart
endpoint: ${baseUrl}/${apiVersion}${cartEndpoint}
method: GET
headers: |
{
"X-Session-ID": "${sessionId}"
}
statusCode: 200
responses:
JsonPath: "$.items.length()>0"
- name: Checkout
endpoint: ${baseUrl}/${apiVersion}${checkout}
method: POST
headers: |
{
"Content-Type": "application/json",
"X-Session-ID": "${sessionId}"
}
body: |
{
"paymentMethod": "credit_card",
"shippingAddress": {
"street": "123 Test St",
"city": "Test City",
"zipCode": "12345"
}
}
statusCode: 200
responses:
JsonPath: "$.orderId!=null"
Best Practices
Organizing Tests
- Group related requests in the same scenario
- Use meaningful names for scenarios and requests
- Keep request bodies and headers in separate files for reusability
- Organize test resources logically
Test Configuration
- Set appropriate thread counts based on expected load
- Use a reasonable ramp-up period to avoid sudden load spikes
- Define common variables at the appropriate level
- Set realistic think times between requests
Validation
- Always specify the expected status code
- Add response validation for critical requests
- Use JSON Path expressions to verify specific response elements
- Set appropriate success thresholds
Performance Considerations
- Start with a small number of threads and gradually increase
- Monitor system resources during test execution
- Consider the test environment's capacity when setting load parameters
- Focus on realistic user scenarios rather than extreme load testing
Data Management
- Use variables for data that changes between environments
- Consider using data files for large datasets
- Handle test data cleanup to avoid affecting subsequent test runs
- Use dynamic data generation for unique values