Skip to content

Chapter 2 · Installation and First Script ​

Chapter goals: Understand the basic structure of locustfile.py, master the three core concepts — HttpUser class, @task decorator, and between() wait time — and write and run your first complete load test.

2.1 Minimal locustfile Structure ​

A valid locustfile needs to satisfy only one rule: at least one class inheriting from User (or its subclass HttpUser).

python
# locustfile.py
from locust import HttpUser, task, between


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

    @task
    def hello_world(self):
        self.client.get("/hello")
        self.client.get("/world")

    @task(3)
    def view_items(self):
        for item_id in range(10):
            self.client.get(f"/item?id={item_id}", name="/item")

    def on_start(self):
        self.client.post("/login", json={"username": "foo", "password": "bar"})

This code contains four core Locust concepts, each unpacked below.

2.2 HttpUser: Simulating One User ​

HttpUser is Locust's built-in user class, designed specifically for HTTP load testing. When the test starts:

  1. Locust creates an instance of this class for each virtual user;
  2. Each instance gets a client attribute — an HttpSession instance responsible for issuing HTTP requests;
  3. Each user runs in its own greenlet coroutine, non-blocking to each other.
python
class MyUser(HttpUser):
    host = "https://httpbin.org"  # Default host declared on the class

    @task
    def get_ip(self):
        resp = self.client.get("/ip")  # Equivalent to requests.get("https://httpbin.org/ip")
        print(resp.json())

Relationship between client and requests

self.client.get() / .post() parameter signatures are nearly identical to the requests library (supporting headers, json, params, etc.). If you've completed the HTTP Requests course on this site, you can migrate seamlessly.

2.3 @task: Declaring Tasks ​

Methods decorated with @task are the virtual user's "behaviors." Each user loops through these methods, randomly picking one each time:

python
@task
def browse_homepage(self):
    self.client.get("/")


@task(3)  # Weight of 3
def browse_product(self):
    self.client.get("/product/1")

@task(3) means this task is 3× more likely to be selected than a weight-1 task — simulating the real-world scenario where "users browse products more frequently than the homepage."

2.4 between(): Controlling Think Time ​

Real users don't bombard the target system non-stop like robots. The wait_time attribute defines the pause between tasks:

python
from locust import between

wait_time = between(1, 5)  # Randomly wait 1–5 seconds after each task

Without wait time, all users would hammer the target system at maximum speed — that's stress testing, not load testing. Chapter 4 covers more wait strategies in detail.

2.5 Running and Viewing Results ​

Save the script as locustfile.py and run from the terminal:

bash
$ locust
[INFO] Starting web interface at http://0.0.0.0:8089

Open your browser to http://localhost:8089:

  1. Number of users: total concurrent users (e.g., 50)
  2. Ramp up: new users per second (e.g., 5/s)
  3. Host: target address (e.g., https://httpbin.org)

After clicking Start, switch to the Charts tab to see three real-time curves:

  • RPS: requests per second
  • Response Times: median and percentile response times
  • Number of Users: currently running virtual users

How to tell if you've hit the bottleneck

If RPS stops growing but response time rises sharply, the target system is saturated. If response time stays flat and RPS hasn't met the target, you need to press harder.

2.6 Chapter Summary ​

  • A locustfile is just a regular Python module; it needs at least one User subclass;
  • HttpUser.client issues requests with the same API as requests;
  • @task decorator declares tasks; @task(N) controls selection probability;
  • wait_time = between(1, 5) simulates real user think pauses;
  • Web UI defaults to port 8089; Charts tab shows RPS / response time / user count in real time.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. What does a valid locustfile minimally need to contain?

2. What does the number 3 mean in @task(3)?

3. What does wait_time = between(1, 5) represent?

4. What type is the self.client attribute on an HttpUser instance?

🛠️ Hands-On Exercises ​

  1. Write a locustfile with two tasks: one GET /get (weight 1), one POST /post (weight 2), targeting https://httpbin.org.
  2. Run it in the Web UI with 10 users / 2 spawn-rate; screenshot and record the RPS and response time curves.
  3. Remove the wait_time = between(1, 5) line and run again; compare RPS changes and explain why.

Proceed to Chapter 3.