Assertions & Response Validation
Your load test shows 0% errors. Great news, right? Not necessarily.
The server returned 200 OK for every request. But buried in those responses:
{
"success": false,
"error": "Product out of stock",
"errorCode": "INVENTORY_001"
}
Without assertions, JMeter counts this as a success. Your "passing" test hides critical failures.
The Silent Failure Problem
E-commerce applications often return 200 OK with error details:
| Response | JMeter Default | Reality |
|---|---|---|
200 + {"success": true} | Pass | Actual success |
200 + {"success": false, "error": "..."} | Pass | Hidden failure |
| 200 + Empty cart (expected items) | Pass | Cart bug |
| 200 + Wrong price | Pass | Pricing error |
Response Assertion
The most versatile assertion. Validates any part of the response.
Check Status Code
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion"
testname="Verify 200 OK">
<collectionProp name="Asserion.test_strings">
<stringProp name="49586">200</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_code</stringProp>
<intProp name="Assertion.test_type">2</intProp>
</ResponseAssertion>
Check Response Body Contains Text
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion"
testname="Verify Success Response">
<collectionProp name="Asserion.test_strings">
<stringProp name="1">"success":true</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<intProp name="Assertion.test_type">2</intProp>
</ResponseAssertion>
Check Response Does NOT Contain Error
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion"
testname="Verify No Errors">
<collectionProp name="Asserion.test_strings">
<stringProp name="1">"error":</stringProp>
<stringProp name="2">Exception</stringProp>
<stringProp name="3">failed</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<intProp name="Assertion.test_type">6</intProp>
<!-- Type 6 = NOT Contains -->
</ResponseAssertion>
Assertion Test Types
| Type Value | Meaning |
|---|---|
| 2 | Contains |
| 1 | Matches (regex) |
| 8 | Equals |
| 6 | NOT (modifier, combine with above) |
| 16 | Substring |
JSON Assertion
Purpose-built for JSON API responses. More precise than text matching.
Verify JSON Field Value
// Response to validate:
{
"order": {
"id": "ORD-123",
"status": "confirmed",
"items": [
{"productId": "PROD-001", "quantity": 2}
],
"total": 159.98
}
}
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion"
testname="Verify Order Confirmed">
<stringProp name="JSON_PATH">$.order.status</stringProp>
<stringProp name="EXPECTED_VALUE">confirmed</stringProp>
<boolProp name="JSONVALIDATION">true</boolProp>
<boolProp name="EXPECT_NULL">false</boolProp>
<boolProp name="INVERT">false</boolProp>
</JSONPathAssertion>
Verify Field Exists
<JSONPathAssertion guiclass="JSONPathAssertionGui" testclass="JSONPathAssertion"
testname="Verify Order ID Exists">
<stringProp name="JSON_PATH">$.order.id</stringProp>
<stringProp name="EXPECTED_VALUE"></stringProp>
<boolProp name="JSONVALIDATION">false</boolProp>
<boolProp name="EXPECT_NULL">false</boolProp>
</JSONPathAssertion>
Leave EXPECTED_VALUE empty and set JSONVALIDATION=false to just check existence.
Verify Array Has Items
<JSONPathAssertion testname="Verify Cart Has Items">
<stringProp name="JSON_PATH">$.order.items[*]</stringProp>
<stringProp name="EXPECTED_VALUE"></stringProp>
<boolProp name="JSONVALIDATION">false</boolProp>
</JSONPathAssertion>
This fails if the items array is empty.
Verify Numeric Value
<JSONPathAssertion testname="Verify Total Greater Than Zero">
<stringProp name="JSON_PATH">$.order.total</stringProp>
<stringProp name="EXPECTED_VALUE">0</stringProp>
<boolProp name="JSONVALIDATION">true</boolProp>
<boolProp name="ISREGEX">false</boolProp>
</JSONPathAssertion>
For numeric comparisons, use JSR223 Assertion for more control.
Duration Assertion
Enforces response time SLAs. Critical for performance testing.
Basic Duration Check
<DurationAssertion guiclass="DurationAssertionGui" testclass="DurationAssertion"
testname="Response Under 3 Seconds">
<stringProp name="DurationAssertion.duration">3000</stringProp>
</DurationAssertion>
Any request taking longer than 3000ms (3 seconds) fails.
E-commerce SLA Examples
| Endpoint | SLA | Duration Value |
|---|---|---|
| Product listing | < 2 seconds | 2000 |
| Product details | < 1.5 seconds | 1500 |
| Add to cart | < 1 second | 1000 |
| Checkout | < 5 seconds | 5000 |
| Payment | < 10 seconds | 10000 |
<!-- Place inside each request, or use different Thread Groups -->
<DurationAssertion testname="Product API SLA">
<stringProp name="DurationAssertion.duration">2000</stringProp>
</DurationAssertion>
Size Assertion
Validates response size. Useful for detecting truncated responses or empty pages.
<SizeAssertion guiclass="SizeAssertionGui" testclass="SizeAssertion"
testname="Response Not Empty">
<stringProp name="Assertion.test_field">SizeAssertion.response_data</stringProp>
<stringProp name="SizeAssertion.size">100</stringProp>
<intProp name="SizeAssertion.operator">4</intProp>
<!-- Operator 4 = Greater Than -->
</SizeAssertion>
| Operator | Meaning |
|---|---|
| 1 | Equal |
| 2 | Not Equal |
| 3 | Greater Than |
| 4 | Less Than |
| 5 | Greater Than or Equal |
| 6 | Less Than or Equal |
JSR223 Assertion (Groovy)
For complex validation logic that built-in assertions can't handle.
Validate Cart Total Calculation
import groovy.json.JsonSlurper
def response = prev.getResponseDataAsString()
def json = new JsonSlurper().parseText(response)
// Calculate expected total from items
def expectedTotal = 0
json.cart.items.each { item ->
expectedTotal += item.price * item.quantity
}
// Add tax (assuming 10%)
expectedTotal = expectedTotal * 1.10
// Compare with returned total (allowing for rounding)
def actualTotal = json.cart.total
def tolerance = 0.01
if (Math.abs(actualTotal - expectedTotal) > tolerance) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage(
"Cart total mismatch! Expected: ${expectedTotal}, Actual: ${actualTotal}"
)
}
Validate Inventory Decreased
import groovy.json.JsonSlurper
def response = prev.getResponseDataAsString()
def json = new JsonSlurper().parseText(response)
// Get previous stock level (stored by earlier extractor)
def previousStock = vars.get("previousStock") as Integer
def currentStock = json.product.stockLevel as Integer
def orderedQuantity = vars.get("orderQuantity") as Integer
def expectedStock = previousStock - orderedQuantity
if (currentStock != expectedStock) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage(
"Stock not decremented correctly. " +
"Previous: ${previousStock}, Ordered: ${orderedQuantity}, " +
"Expected: ${expectedStock}, Actual: ${currentStock}"
)
}
Validate Response Time Percentile
// Check that this request's time is within reasonable bounds
def responseTime = prev.getTime()
def p95Threshold = 3000 // 3 seconds
if (responseTime > p95Threshold) {
// Log warning but don't fail (P95 allows 5% to exceed)
log.warn("Response time ${responseTime}ms exceeded P95 threshold")
// Optionally track for later analysis
def slowCount = vars.get("slowRequestCount") ?: "0"
vars.put("slowRequestCount", (slowCount.toInteger() + 1).toString())
}
Assertion Placement Strategy
Per-Request Assertions
Place specific assertions under individual requests:
Thread Group
├── Login Request
│ └── JSON Assertion: Check auth token exists
├── Get Products
│ └── JSON Assertion: Check products array not empty
│ └── Duration Assertion: Under 2 seconds
└── Checkout
└── JSON Assertion: Check order confirmed
└── Duration Assertion: Under 5 seconds
Thread Group-Level Assertions
Apply to ALL requests in the group:
Thread Group
├── Response Assertion: No error messages (applies to all)
├── Duration Assertion: Under 10 seconds (applies to all)
├── Login Request
├── Get Products
└── Checkout
E-commerce Assertion Checklist
- Login: Token/session returned, no error field
- Product List: Array not empty, products have IDs and prices
- Add to Cart: Cart ID returned, item count increased
- Cart Total: Total > 0, matches item sum
- Checkout: Order ID returned, status is "confirmed" or "pending"
- Payment: Transaction ID returned, no payment errors
- All Endpoints: Response time within SLA
Debugging Failed Assertions
View Results Tree
Failed assertions show in red. Click to see:
- Request tab: What was sent
- Response tab: What came back
- Assertion Results tab: Why it failed
Assertion Results Listener
Add this listener for detailed assertion failure tracking:
<ResultCollector guiclass="AssertionVisualizer" testclass="ResultCollector"
testname="Assertion Results">
<boolProp name="ResultCollector.error_logging">true</boolProp>
</ResultCollector>
Key Takeaways
- Status codes lie: Always validate response body content, not just HTTP status.
- JSON Assertion for APIs: More precise and maintainable than text matching.
- Duration Assertion for SLAs: Enforce response time requirements during load tests.
- Groovy for complex logic: Calculate expected values, compare related fields, validate business rules.
Next Lesson
You can now validate that your application works correctly under load. Time to put it all together: E-Commerce Load Scenarios - building complete user journey tests from browsing to checkout, including flash sale simulations.