Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I perform Load testing with Locust using PyTest?

What do you think is it possible to perform Load testing using PyTest? For example:

import locust

class UsersTest(locust.TaskSet):

    @locust.seq_task(1)
    def api_get_task(self):
        self.client.get("/api", name="GET /api") # Самое действие

    @locust.seq_task(2)
    def api_post_task(self):
        payload = {"username": "user1", "password": "123456"}
        self.client.post("/api", data=payload, name="POST /api")

class SituationTest(locust.HttpLocust):

    task_set = UsersTest 
    min_wait = 1000 
    max_wait = 2000
    host = "http://127.0.0.1:3000"

So here is example of 2 simple tasks for 2 urls. Into class UsersTest I have my test cases itself. Into class SituationTest I have my params.

So question is how to integrate this 2 classes into pytest fixtures decorators and split it between test_file.py and conftest.py?

like image 435
Anton Lisetsky Avatar asked Apr 30 '19 05:04

Anton Lisetsky


2 Answers

Also, you can use locust as a library instead of as a CLI.

import gevent
import locust


class UsersTest(locust.SequentialTaskSet):

    @locust.task
    def api_get_task(self):
        self.client.get("/api", name="GET /api")  # Самое действие

    @locust.task
    def api_post_task(self):
        payload = {"username": "user1", "password": "123456"}
        self.client.post("/api", data=payload, name="POST /api")


class SituationTest(locust.HttpUser):

    task_set = UsersTest
    min_wait = 1000
    max_wait = 2000
    host = "http://127.0.0.1:3000"


def test__your_pytest_example():
    env = locust.env.Environment(user_classes=[SituationTest])
    env.create_local_runner()
    gevent.spawn(locust.stats.stats_history, env.runner)
    env.runner.start(1, spawn_rate=1)
    gevent.spawn_later(10, lambda: env.runner.quit())
    env.runner.greenlet.join()

    assert env.stats.total.avg_response_time < 60
    assert env.stats.total.num_failures == 0
    assert env.stats.total.get_response_time_percentile(0.95) < 100

Check the official doc: https://docs.locust.io/en/stable/use-as-lib.html

like image 129
Darío López Padial Avatar answered Sep 30 '22 18:09

Darío López Padial


One possible way to do this by adding individual pytest tests as a locust task.

If you tests are simple and don't use pytest fixtures, you can import all test functions(or classes) and add them as tasks.

Here is how you can add a task programmatically.

Resulting code would be something of this effect.

from test_module import test_a
from locust import TaskSet, HttpLocust


class TestTaskSet(TaskSet):
     @task
     def test_task(self):
         self.schedule_task(test_a)


class WebsiteUser(HttpLocust):
    task_set = TestTaskSet

If your test code uses pytest features like fixtures, parameterization etc., you can use pytest.main() to collect all the tests and add individual tests as tasks and execute them as pytest tests.

e.g.

import pytest
from locust import TaskSet, HttpLocust, between


class TestCollector:

    def __init__(self):
        self.collected = []

    def pytest_collection_modifyitems(self, items):
        for item in items:
            self.collected.append(item.nodeid)


test_collector = TestCollector()

pytest.main(['tests_dir', '--collect-only'], plugins=[test_collector])


class TestTaskSet(TaskSet):

    @task
    def task_gen(self):
        for test in test_collector.collected:
            self.schedule_task(pytest.main, args=[test])


class WebsiteUser(HttpLocust):
    task_set = TestTaskSet
    wait_time = between(1, 5)

This code will make individual tests a locust task.

like image 43
SilentGuy Avatar answered Sep 30 '22 18:09

SilentGuy