Locust: A Scalable and Easy-to-Use Load Testing Tool
This article guides you on how the Locust performance testing tool work.
By Ambrose P— “A humble quality pursuer”
Performance Testing
Load testing is critical to software development, as it ensures that the application can handle the expected load and delivers a satisfactory user experience. There are many load testing tools available in the market, but the one rising in popularity is Locust.
What is Locust?
Locust is an open-source load testing tool written in Python, designed to simulate a large number of concurrent users for all kinds of user behavior. Locust gets its name from the species of grasshopper known for their behavior of swarming in groups.
Why Locust?
Ease-of-Use: Locust is a lightweight tool that does not use any complex GUI to perform the test. Rather each scenario can be scripted with basic Python.
Scalable and Supports Distributed Load Generation: In Locust, it is easy to run load test scripts distributed over multiple machines with one --master
and multiple --worker
nodes. Thus making it possible to generate hundreds and thousands of users.
Dynamic and Adjustable Workload: Locust supports dynamic workload adjustments during test execution which is not found in other performance testing tools. This means we can change the number of users, the spawn rate, or any other aspects of the test on the fly.
Web-Based UI: Locust provides a web-based user interface that displays real-time statistics and metrics during test execution. This interface allows us to monitor the performance of the application, track the number of requests per second, and response times, and download the test report and exception logs as well.
Setting up Locust
Python 3.7 or greater is a prerequisite for Locust. Now to install the Locust package run the following command in the terminal.
pip3 install locust
Scripting a Basic Locust file
Once Python and Locust are set up, we can start scripting our Locust file. The two basics of Python which is a must in preparation for locust file are class
function and def
method blocks.
Here is a simple example Locust file for performing a load test on a set of user behavior tasks where the user logs in and searches for a customer email.
from locust import HttpUser, task, between, SequentialTaskSet
class CustomerProfile(SequentialTaskSet):
@task
def login(self):
payload = {"agent": {"email": "ur_email", "password": "ur_password"} }
login_header = {"Content-Type": "application/json"}
loginResponse = self.client.post("/login", json=payload, headers=login_header, name="login")
print("Login Response Code : ", loginResponse.status_code) @task
def search_email(self):
cx_header = {"accept": "*/*"}
cxProfilesResponse = self.client.get('/ur_endpoint_path/ur_query_parameter', headers=cx_header, name="cxProfile")
print("cx Profiles Response Code : ", cxProfilesResponse.status_code)
print("cx Profiles Response Value : ", cxProfilesResponse.text)
class ProfileSearch(HttpUser):
tasks = [CustomerProfile]
host = "https://enter_ur_host_url"
wait_time = between(2, 5
So let’s break down the Locust file for a better understanding
from locust import HttpUser, task, between, SequentialTaskSet
- The Locust file is just a normal Python file so we can import code from any different package to suit our test scenario. Here we are importing packages from locust to our Python project.
class CustomerProfile(SequentialTaskSet):
@task
def login(self):
. . . . . .
@task
def search_email(self):
. . . . . .
- Here in the above snippet, we are creating a class named CustomerProfile which inherits the class
SequentialTaskSet
provided by Locust, this is so that multiple different tasks work sequentially to perform actions like a real user. In our above scenario the user first logs into their profile and then only will search for the customer email. @task
decorator is used to convert a method into a task. The decorator is provided by Locust.
def login(self):
payload = {.......}
headers = {.......}
self.client.post("/login", json=payload, headers=headers, name="login")
- This is a method block that is used to perform the different API request tasks. The self.client is a built-in attribute of Locust which then calls the get/post/put methods to perform API requests. We can also inject these data from CSV/Json files too.
wait_time = between(2, 5)
- The
wait_time
is an attribute that is introduced to give breathing time in between each request so that there is not too much stress on the application. If no wait_time is provided each task executes one after the other. The methods present to provide the wait_time arebetween
andconstant
.
class ProfileSearch(HttpUser):
tasks = [CustomerProfile]
host = ". . . . . ."
- This is the main execution class that inherits
HttpUser
class provided by Locust to create HTTP clients which act as real-time users who perform the tasks provided. The host URL is declared within the host variable.
Running the locust file
The locust file execution can be performed using the below command line in the IDE terminal.
locust -f ur_file.py
Here the -f flag is used to specify the path to the locust file hence replace ur_file.py with the locust file which is to be executed. This command starts the server for load testing.
Locust Web Interface
Once the server is started, open http://localhost:8089 to access the Locust interactive web interface. This is where all the magic happens in front of our eyes.
There are multiple different ways through which the load (spawns and spawn rate) can be implemented. As we can see the web interface shows the input for the number of users and spawn rate, which is one way we can set directly in here and can also be edited during test execution itself. But these inputs can also be given directly through the command line.
locust -f ur_file.py --users 50 --spawn-rate 10
Custom Load Generation: This is another way of load implementation which helps in providing custom-shaped loads that we might want to use in cases where the need to generate load spikes or ramp-ups and downs at custom time intervals. This can be achieved by inheriting the LoadTestShape
class provided by Locust. More detailed documentation will be made in the near future, but for now, here is a sample file used.
class CustomLoadShape(LoadTestShape):
loads = [
{"duration": 60, "users": 10, "spawn_rate": 2},
{"duration": 100, "users": 50, "spawn_rate": 10},
{"duration": 180, "users": 100, "spawn_rate": 12},
{"duration": 220, "users": 30, "spawn_rate": 10},
{"duration": 230, "users": 10, "spawn_rate": 4},
{"duration": 240, "users": 1, "spawn_rate": 1},
]
def tick(self):
run_time = self.get_run_time()
for load in self.loads:
if run_time < load["duration"]:
tick_data = (load["users"], load["spawn_rate"])
return tick_data
return None
The most useful command to remember is, which outputs all the helpful additions that can be used when executing the locust file.
Once the Start Swarming button is clicked, the load testing process starts and a new page is loaded.
The above is the page that shows the statistics and metrics of the load which is being applied to the endpoints given in the locust file. Here the tabs present are Statistics, Charts, Failures, Exceptions, Current Ratio, Download Data, and each of them are self-explanatory. The load can be changed by clicking on the edit button whenever needed.
Above are the charts providing real-time data of the performance test, detailing how many requests per second are hit, what their response times(ms) and how many concurrent HTTP users are accessing the application at the moment.
The test execution can be stopped by either clicking the stop button at the top RHS of the interface or by entering ctrl+c
in the IDE terminal to stop the server altogether.
The data collected here will surely help the developers in stabilizing and strengthening the application to withstand any amount of load.
Conclusion
Locust is a simple yet powerful performance testing tool that helps in ensuring that the application can handle high user loads without any compromise in performance. With its simplicity, scalability, and ability to simulate realistic user behavior, Locust offers a cost-effective and efficient solution for any scale of performance testing.
Give Locust a try for your next performance testing opportunity, and unleash its potential to drive your application’s performance to the fullest!
Thank you and Good Luck!
References
Meet the team!
Author
Editor
We at CaratLane are solving some of the most intriguing challenges to make our mark in the relatively uncharted omnichannel jewellery industry. If you are interested in tackling such obstacles, feel free to drop your updated resume/CV to careers@caratlane.com