🔥 0
0
Lesson 6 of 10 20 min +150 XP

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:

ResponseJMeter DefaultReality
200 + {"success": true}PassActual success
200 + {"success": false, "error": "..."}PassHidden failure
200 + Empty cart (expected items)PassCart bug
200 + Wrong pricePassPricing error
Assertions catch what status codes miss.

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 ValueMeaning
2Contains
1Matches (regex)
8Equals
6NOT (modifier, combine with above)
16Substring

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

EndpointSLADuration Value
Product listing< 2 seconds2000
Product details< 1.5 seconds1500
Add to cart< 1 second1000
Checkout< 5 seconds5000
Payment< 10 seconds10000
<!-- 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>
OperatorMeaning
1Equal
2Not Equal
3Greater Than
4Less Than
5Greater Than or Equal
6Less 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

Critical Assertions for E-commerce
  • 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.

🧠 Quick Quiz

Test your understanding of this lesson.

1

Why isn't a 200 status code sufficient for validation?

2

What does a Duration Assertion validate?

3

Where should you place a Duration Assertion to apply it to all requests?