Locust assertions are the unsung heroes of load testing, turning raw response data into actionable insights about your API’s health.

Imagine you’re testing an e-commerce API. A user logs in, browses products, adds to cart, and checks out. Each of these is an HTTP request. Locust runs these requests in parallel, simulating thousands of users. But just making the requests isn’t enough; you need to know if they’re succeeding. That’s where assertions come in.

Let’s see a basic example in Python, using Locust’s HttpUser class:

from locust import HttpUser, task, between

class WebsiteUser(HttpUser):
    wait_time = between(1, 5)

    @task
    def index(self):
        response = self.client.get("/")
        assert response.status_code == 200, f"Expected status code 200, but got {response.status_code}"

    @task
    def login(self):
        login_data = {"username": "testuser", "password": "password123"}
        response = self.client.post("/login", json=login_data)
        assert response.status_code == 201, f"Login failed. Expected 201, got {response.status_code}"
        assert "token" in response.json(), "Login response missing 'token' key"

In this snippet, assert response.status_code == 200 checks if the HTTP status code of the / endpoint is 200 (OK). If it’s not, the test fails for that specific request, and Locust records it as a failure. The f-string message provides crucial context: "Expected status code 200, but got 404."

The /login task has two assertions:

  1. assert response.status_code == 201: Checks if the login endpoint returns a 201 (Created) status, common for successful resource creation like a new session.
  2. assert "token" in response.json(): This goes deeper. It parses the JSON response body and verifies that a key named "token" exists. This ensures the API is returning the expected authentication token.

When Locust runs, it aggregates these assertion results. If any assertion fails for a request, that request is marked as a failure in Locust’s statistics. This is vital for understanding not just how many requests your system can handle, but how correctly it handles them under load.

The core problem assertions solve is distinguishing between a system that is slow and a system that is broken. A request might return in 10 milliseconds but with a 500 Internal Server Error. Without assertions, you’d just see a fast request. With an assertion checking for 200 or 201, you immediately know something is wrong.

The internal mechanism is straightforward: Locust intercepts the response object returned by self.client (which is typically a requests.Response object under the hood). Before logging the request’s success or failure, it iterates through any assert statements within the task function. If an assert condition evaluates to False, Locust raises an AssertionError. Locust catches this AssertionError, marks the request as failed, and includes the assertion’s message in the failure details.

You have complete control over what you assert. Common checks include:

  • Status Codes: assert response.status_code == 200, assert response.status_code in [200, 201]
  • Response Body Content: assert "Welcome" in response.text, assert response.json()["user"]["id"] == 123
  • Response Headers: assert "Content-Type" in response.headers, assert response.headers["X-RateLimit-Remaining"] > 0
  • Response Time: assert response.elapsed.total_seconds() < 2 (though this is often handled by Locust’s built-in statistics rather than explicit assert statements for every request).

The most powerful aspect is combining these. You might assert that a successful creation (201) also returns a specific ID in the body, and that the Location header points to the created resource.

The one thing most people don’t realize is that assert statements within a Locust task are executed sequentially for a single request. If the first assertion fails, the subsequent assertions for that same request are never reached. This means the order of your assertions matters if you want to catch a cascade of potential issues. For instance, checking for a 200 status code before trying to parse a JSON body prevents JSONDecodeError if the server returns HTML for an error.

Beyond simple assert statements, Locust offers more structured ways to handle assertions, like the expect_json and expect_text methods on the Response object, which simplify common checks and provide clearer error messages.

The next step after mastering assertions is understanding how to use Locust’s event hooks to perform more complex, cross-request validation or to integrate assertion failures into external monitoring systems.

Want structured learning?

Take the full Locust course →