Performance Testing using Python Locust
When building microservices, we usually want to know how it performs under some speciic loads which will be based on the requirement of the business.
In this article we’re going to use Locust which is a Python library to perform load testing of a simple application. We will try to the set the different parameters and see how the service performs.
Before we dive into running performance tests, first we’ll create a very simple flask application which will expose three simple endpoints that we will use to perform load testing.
First let’s install the required python libraries we are going to use
$ pip install flask
$ pip install locust
So let’s first build a small flask app, below is the source code for the same. We’ll create a main.py
file with the content
import flask
from flask import Response, request, jsonify
app = flask.Flask(__name__)
app.config["DEBUG"] = True
data = {
"name": "sandeep",
"city": "siliguri"
}
success_response = 1
@app.route('/user', methods=['GET', 'POST'])
def user():
if request.method == 'GET':
global success_response
success_response += 1
if success_response % 5 == 0:
return Response("Error", status=500)
return jsonify(data)
if request.method == 'POST':
return Response("User Added Successfully", status=200)
@app.route('/version', methods=['GET'])
def version():
response = {"version": 1.0}
return jsonify(response)
app.run()
Let’s just go through what’s happening in this application. We have a dictionary which contains some sample data and we’re using this to return the reponse for the \user
endpoint which has both POST as well as GET mapping. Also for every fifth response in the GET query we’re returning a 500 error response. More on why we’re doing this later.
And then we have another endpoint which just returns the version of our application. So now that we have our application ready we’re going to run it and hit the endpoints.
$ python main.py
We should see our application start successfully
Okay so now we have our application running on port 5000, let’s try to hit the endpoints and check that we’re getting the correct result
$ curl -X GET "localhost:5000/info"
$ curl -X GET "localhost:5000/version"
Great! So our application is ready now. Let’s move on to running performance tests now.
We’ll create a new file called performance.py
from locust import task, between, tag
from locust.user.users import HttpUser
class AppUser(HttpUser):
wait_time = between(5, 15)
host = "http://localhost:5000"
@task(1)
def get_user(self):
self.client.get("/user",)
@task(1)
def post_user(self):
self.client.post("/user", data={"name": "sandeep", "city": "bangalore"})
@task(1)
def version(self):
self.client.get("/version")
Let’s go through what’s happening in this code snippet.
First we import the required modules. Then we create a class called AppUser which will simulate a real user and we’re inheriting the HttpUser class which comes from Locust. The HttpUser class gives us the client that we can use to make the api calls.
Next we’re setting the host to "http://localhost:5000"
because this is location of our flask application.
Then we create a method called get_user
, this is the method that will call the /user
endpoint, we also annotate it with @task
. Inside the method we use the http client that is inherited from HttpUser to make the http call. We pass the path which is appended to the host before making the call.
Similarly the second method post_user
makes a post call. This is similar to the previous method except we’re calling the post method in the http client and we also the pass the data which the post api expects.
The third method is similar to the first one except here we’re calling the version
endpoint.
Now that we have our script ready we can run this to test our application and see how it performs. Let’s run this now
$ locust -f .\performance.py --headless -u 25 -r 8 --run-time 30s
We’re passing a few parameters here, let’s go through them one by one.
First we’re using the --headless
parameter to run the tests in headless mode. Then we use the u
parameter to specify the number of users, here we’re specifying the number of users to be 25. Then the r
parameter is the number of user to spawn every second. And finally the run-time
defines the time for which the tests should run.
Okay so now let’s execute the command. We should see something like this
At the end of the run we should be able to see the results.
We can see number of requests that were fired, the number of failures and the response times. We notice that we have around 5 failures for the get endpoint. This was because we had made a change in our code to return 500 error for every fifth request.
We can also see here the average response time, the minimum reponse time and the max and median.
To get these reports in a csv format we can pass the --csv=result
parameter when running the tests and we will get a CSV file with the name result which will contain all the test statistics.
The entire source code for this post can be found here https://github.com/sandyjswl/performance-testing-using-locust