Here is a harsh truth: a load test without assertions is just an expensive ping. You are confirming the server responded, but not that it responded correctly. I have seen production incidents where the server returned 200 OK with an HTML error page ("Something went wrong, please try again") -- and the performance test passed with flying colors because nobody checked the response body. Assertions are your quality gate inside the test.
The Response Assertion can check almost anything: response code, response body, response headers, and even the response message. It is the most flexible assertion, and you will use it on nearly every request.
Right-click sampler → Add → Assertions → Response Assertion.
Apply to: Main sample only (or sub-samples if testing embedded resources).
Field to Test: choose what to check (Response Code, Response Body, Response Headers, etc.).
Pattern Matching Rules: Contains, Matches (regex), Equals, Substring, Not + any of these.
Patterns to Test: add the expected value(s). Multiple patterns are OR-ed by default.
Custom Failure Message: write a clear message for debugging failures.
| Field to Test | Pattern Matching | Pattern | What It Checks |
|---|---|---|---|
| Response Code | Equals | 200 | HTTP status must be exactly 200 |
| Response Body | Contains | "success": true | Body must contain this string |
| Response Body | NOT Contains | "error" | Body must NOT contain "error" |
| Response Headers | Contains | application/json | Response must be JSON |
| Response Body | Matches | \{"id":\d+.*\} | Body matches this regex |
| Response Message | Equals | OK | HTTP message must be "OK" |
# You can add multiple patterns in one assertion (OR logic):
# Pattern 1: "success"
# Pattern 2: "created"
# Request passes if body contains "success" OR "created"
# For AND logic, add multiple Response Assertions:
# Assertion 1: Body Contains "success"
# Assertion 2: Body Contains "userId"
# Assertion 3: Response Code Equals "200"
# Request passes only if ALL three assertions passWhen testing REST APIs, the JSON Assertion is more precise than Response Assertion. It uses JSONPath expressions to validate specific fields in the JSON response. Instead of checking if the body "contains" a string (which could match anywhere), you check if a specific JSON field has a specific value.
# Add: Right-click sampler → Assertions → JSON Assertion
# Example 1: Check that user name exists and is not null
Assert JSON Path exists: $.user.name
Additionally assert value: (unchecked -- just check existence)
# Example 2: Check that status equals "active"
Assert JSON Path exists: $.status
Expected Value: active
Match as regular expression: false
# Example 3: Check that items array has at least one element
Assert JSON Path exists: $.items[0]
# Example 4: Check that price is a specific value
Assert JSON Path exists: $.product.price
Expected Value: 29.99
# Example 5: Check with regex (match any UUID)
Assert JSON Path exists: $.orderId
Expected Value: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
Match as regular expression: true
# API Response being validated:
# {
# "user": { "name": "John", "role": "admin" },
# "status": "active",
# "items": [{ "id": 1 }, { "id": 2 }],
# "product": { "price": 29.99 },
# "orderId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
# }If you are testing SOAP web services or XML APIs, the XPath Assertion is your tool. It works like JSON Assertion but for XML documents. While REST APIs have largely replaced SOAP, many enterprise systems (banking, insurance, healthcare) still use SOAP heavily. If your company deals with legacy systems, you will encounter this.
<!-- API Response -->
<response>
<status>success</status>
<user>
<id>42</id>
<name>John Doe</name>
</user>
<balance currency="USD">1500.00</balance>
</response>
<!-- XPath Assertions -->
<!-- Check status is "success": -->
<!-- XPath: //status/text() = 'success' -->
<!-- Check user ID exists: -->
<!-- XPath: //user/id -->
<!-- Check balance currency attribute: -->
<!-- XPath: //balance/@currency = 'USD' -->The Duration Assertion fails a request if it takes longer than a specified time. This is the assertion that turns your test from "did it work?" into "did it work fast enough?". Every production SLA I have seen defines acceptable response times. The Duration Assertion enforces them automatically.
# Add: Right-click sampler → Assertions → Duration Assertion
Duration in milliseconds: 2000
# Any request taking longer than 2 seconds = FAILED
# Appears as red in View Results Tree with:
# "Assertion failure message: The operation lasted too long: It took 3,421 ms"
# Pro tip: Use different thresholds for different request types:
# API calls: 500ms - 1000ms
# Page loads: 2000ms - 3000ms
# File downloads: 5000ms - 10000ms
# Report generation: 10000ms - 30000msSometimes you need custom validation logic. Maybe you need to check that a timestamp is within the last 5 minutes, or that a list is sorted, or that a calculated field matches a formula. The JSR223 Assertion lets you write Groovy code (or Java, JavaScript) to perform any validation you can imagine.
// Access the response
import groovy.json.JsonSlurper
def response = prev.getResponseDataAsString()
def json = new JsonSlurper().parseText(response)
// Check that items array has between 1 and 100 items
def itemCount = json.items.size()
if (itemCount < 1 || itemCount > 100) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage(
"Expected 1-100 items, got ${itemCount}"
)
}
// Check that all prices are positive
def negativePrices = json.items.findAll { it.price <= 0 }
if (negativePrices.size() > 0) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage(
"Found ${negativePrices.size()} items with non-positive prices"
)
}
// Check that response time is under SLA
def slaMs = vars.get("EXPECTED_SLA_MS") as int
if (prev.getTime() > slaMs) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage(
"Response time ${prev.getTime()}ms exceeded SLA of ${slaMs}ms"
)
}JSR223 Assertions run for EVERY request in scope. Complex Groovy scripts with JSON parsing add overhead to each request. In a 1000-thread test, a script that takes 5ms per request adds 5 seconds of total processing per second. Use built-in assertions whenever possible. Reserve JSR223 for validations that truly cannot be done with Response, JSON, or Duration assertions.
When an assertion fails, the request is marked as FAILED in all listeners and reports -- even if the HTTP status was 200 OK. This means your error rate in the Summary Report reflects both HTTP errors (500, timeout) and business logic errors (wrong response body, too slow). This is exactly what you want. A "successful" response that returns garbage data is a failure from the user's perspective.
Q: What assertions do you add to your JMeter test plans, and why?
A: I add three types of assertions to every test. First, a Response Assertion checking the status code (200 for GET, 201 for POST) and verifying the body does not contain error strings. Second, a JSON Assertion (for API tests) validating that key response fields exist and have expected values -- for example, that a login response contains a token field and a user object. Third, a Duration Assertion matching our SLA threshold -- typically 2 seconds for API calls and 5 seconds for page loads. The Duration Assertion is the most important one because without it, you can have a test with 0% error rate but 30-second response times, which would still be a production disaster. For complex validations, I occasionally use JSR223 Assertions with Groovy -- for example, verifying that a list is sorted or that a calculated total matches the sum of line items.
Key Point: Always add assertions. Response Assertion for status and body checks, JSON Assertion for API field validation, Duration Assertion for SLA enforcement. A test without assertions is just a ping test.
Key Point: Response Assertion (status/body), JSON Assertion (API fields), Duration Assertion (SLA). A 200 OK with wrong content is still a failure.