Writing Extendable Load Tests for Your Customer Facing Applications

Updated

For customer facing applications for which you do not know the amount of customers you might reach, you should ensure that your system can handle at least some expected load.

But what if over time your application evolves? Maintaining a loadtest setup can be a valid overhead. Lucky you, it is an overhead that can be reduced drastically.

In this article you can expect:

An language agnostic view on how a load-test should be structured to make it future proof and keep it maintainable.

How to Structure Your Load Test?

To get a realistic load test I propose to structure the load test based on user flows.

If you have a UI that does multiple requests to a backend based on some user action, then this is the overall domain that you want to load test. You want to know if the users can use the system as expected under the circumstance that many other users do the same thing. So test exactly this scenario.

I propose abstracting load test heavily. They should represent your architecture in the way your users experience it first hand. Lets imagine the architecture that you want to load test looks like the following figure:

load-test-setup

Your load test should not know about service a, b, c. But it should know about your “Backend for Frontend”.

In your load test you can create a class or representation of the UI with its actions. Additionally you can create a class or representation of the backend for frontend and its actions.

Lets imagine that you want to test an application in which a user can search for offers, select one and buy it. Your goal should be that your code looks like this:

0def load_test():
1    mock_backend = new Backend()
2    mock_ui = new UI(mock_backend)
3    mock_ui.search_for_offers()
4    mock_ui.select_offer()
5    mock_ui.buy_offer()
6
7
8class UI:
9    def __init__(self, backend):
10        self.backend = backend
11
12    def search_for_offers():
13        backend.get_offers()
14    def select_offer():
15        backend.post_offer_selection()
16    def buy_offer():
17        backend.post_order()
18
19
20class Backend:
21    def get_offers():
22    # do actual request
23    def post_offer_selection():
24    # do actual request
25    def post_order():
26# do actual request

This way you can modify the flow very easily and keep your code extendable. You added a new call to a user flow? Just add it into the backend endpoints in the ‘Backend’ class and use it in the user action that you have in your UI class. This way you have a very structured integration of your applications flow in your load tests. I would even go one step further and wait between the actions in random time intervalls that can also be monitored in production. No user directly interacts with the next action in a UI. It should be modelled properly in your load test.

I personally had very good experiences in the last 2 years with this load test approach and I hope it helps you as well.