Chapter 6 · Assertions and Failure Detection
Chapter goals: Master request-level assertions with
catch_response=True, manually mark failures withresp.failure(), aggregate statistics withname=, and build reliable pass/fail logic.
6.1 Why Assertions Matter
By default, Locust only judges success/failure by HTTP status code: 2xx is success, 4xx/5xx is failure. But in production, "returning 200 with wrong data" is very common — for example, an API returns {"code": 500, "msg": "Internal error", "data": null} with HTTP status 200.
A load test without assertions is like a temperature check without a thermometer: you see all requests "succeed", but the system may already be broken.
from locust import HttpUser, task, between
class ApiUser(HttpUser):
wait_time = between(1, 3)
host = "https://api.example.com"
@task
def get_user(self):
# Default behavior: only checks HTTP status code
self.client.get("/api/users/1")
# Status 200 → marked successful (even if body contains error info)6.2 catch_response=True
Pass catch_response=True to self.client.get() / .post() and other methods — Locust pauses automatic marking, letting you decide success or failure manually:
from locust import HttpUser, task, between
import json
class ApiUser(HttpUser):
wait_time = between(1, 2)
host = "https://api.example.com"
@task
def get_user_with_assertion(self):
with self.client.get("/api/users/1", catch_response=True) as resp:
# Assertion 1: HTTP status must be 200
if resp.status_code != 200:
resp.failure(f"Status code error: {resp.status_code}")
return
# Assertion 2: response body must be valid JSON
try:
data = resp.json()
except json.JSONDecodeError:
resp.failure("Response is not valid JSON")
return
# Assertion 3: business code must be 0
if data.get("code") != 0:
resp.failure(f"Business error: code={data.get('code')}, msg={data.get('msg')}")
# Assertion 4: required field exists
if "data" not in data or not data["data"]:
resp.failure("data field missing or empty")The with ... as resp syntax is Python's context manager. Entering the with block pauses Locust stats; exiting marks success/failure based on whether you called resp.failure().
The success() method
You can explicitly call resp.success() to mark success, but it is not required — as long as you didn't call failure(), Locust auto-marks success on exiting the block.
6.3 Custom Stat Names (name= Parameter)
When URLs contain dynamic path params (e.g., /api/users/12345), each different ID generates a separate stat row, causing table explosion. Use name= to aggregate them:
import random
from locust import HttpUser, task, between
class SearchUser(HttpUser):
wait_time = between(1, 3)
host = "https://api.example.com"
@task
def search_products(self):
product_id = random.randint(1, 10000)
# Without name= → 10,000 different URL rows in stats
# With name= → all requests aggregated into one "/api/products/[id]" row
with self.client.get(
f"/api/products/{product_id}",
name="/api/products/[id]",
catch_response=True
) as resp:
if resp.status_code == 200:
data = resp.json()
if data.get("price") is None:
resp.failure("Price field missing")
else:
resp.failure(f"HTTP {resp.status_code}")6.4 Chapter Summary
catch_response=Truepauses auto-marking for custom business validation;resp.failure(msg)marks a failure with a custom message;resp.success()is optional;name=aggregates dynamic URL paths into one stat row — essential for meaningful percentiles;- Always validate both HTTP status AND response body for production-grade tests.
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. What does catch_response=True do?
2. If you do not call resp.failure() inside a catch_response block, what happens on exit?
3. Why is name= critical when testing endpoints with dynamic IDs?
4. What is the difference between HTTP status validation and body validation?
🛠️ Hands-On Exercises
- Write a test that validates both HTTP status AND response body for a JSON API; mark failure on missing fields.
- Add
name="/api/users/[id]"to a loop over 100 user IDs; verify the stats table has one row instead of 100. - Combine
catch_response=Truewithname=in a single task; assert status code, JSON validity, and business code in one block.
Proceed to Chapter 7: TaskSet and Nested Tasks.