本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。

Tasks 和 Events 是 Locust 性能测试工具的核心技术,有了它们,Locust 才能称得上是一个性能工具。

Tasks

从上篇文章知道,locustfile 里面必须要有一个类,继承 User 类,当性能测试开始后,会产生一个 User 类实例,这就是常说的模拟用户。这些用户会选择 task 执行,休眠一会,再选择新的 task,不断迭代。

task 是 Python 中的可调用对象,它是一项任务,对于 Web 系统来说,可以是登录、查询、下订单、支付等等。

@task 装饰器

@task 是定义 task 最简单直接的方式,比如:

from locust import User, task, constant

class MyUser(User):
    wait_time = constant(1)

    @task
    def my_task(self):
        print("User instance (%r) executing my_task" % self)

@task 有一个可选参数,用来设置 task 的选择权重,比如:

from locust import User, task, between

class MyUser(User):
    wait_time = between(5, 15)

    @task(3)
    def task1(self):
        pass

    @task(6)
    def task2(self):
        pass

task2 比 task1 被选择的可能性大两倍。

tasks 属性

除了@task 装饰器,还可以设置 User 类的 tasks 属性来定义任务,比如:

from locust import User, constant

def my_task(user):
    pass

class MyUser(User):
    tasks = [my_task]
    wait_time = constant(1)

注意,my_task()函数有一个参数,它是 User 类的实例。

tasks 可以是一个列表:

tasks = [my_task1, my_task2, my_task3]

Locust 会使用 Python 中的 random.choice()从里面随机选取。

tasks 也可以是一个字典:

{my_task: 3, another_task: 1}

后面的 int 型键值代表的是被选择权重,这个字典等价于列表:

[my_task, my_task, my_task, another_task]

@tag 装饰器

@tag 用来打标记,在运行时选择哪些 task 执行,哪些 task 不执行。比如:

class MyUser(User):
    wait_time = constant(1)

    @tag('tag1')
    @task
    def task1(self):
        pass

    @tag('tag1', 'tag2')
    @task
    def task2(self):
        pass

    @tag('tag3')
    @task
    def task3(self):
        pass

    @task
    def task4(self):
        pass
  • 如果使用--tags tag1,那么只有 task1 和 task2 会被选择。
  • 如果使用--tags tag2 tag3,那么只有 task2 和 task3 会被选择。
  • 如果使用--exclude-tags tag3,那么只有 task1、task2 和 task4 会被选择。

注意,exclude 的优先级更高,如果某个 tag 既包括又排除,那么会被排除。

Events

@task 定义了性能测试的执行动作,@events 作为补充,定义了测试开始前和测试结束后的处理。

注意,每个模拟用户开始和结束的处理是使用的 User 类的 on_start()和 on_stop()方法。

test_start 和 test_stop

测试开始前和测试结束后触发。示例:

from locust import events

@events.test_start.add_listener
def on_test_start(environment, **kwargs):
    print("A new test is starting")

@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
    print("A new test is ending")

分布式执行时,它们只会在 master 节点生效。

init

init 和 test_start 不同,它会在每个 Locust 进程开始时触发,分布式执行时,每个节点(worker 进程)都会生效。

from locust import events
from locust.runners import MasterRunner

@events.init.add_listener
def on_locust_init(environment, **kwargs):
    if isinstance(environment.runner, MasterRunner):
        print("I'm on master node")
    else:
        print("I'm on a worker or standalone node")

Events 是一项 hook 技术,在学习 Locust 高级用法时再做进一步介绍。

Locust 项目结构

官方建议如下:

common/

__init__.py

auth.py

config.py

locustfile.py或者locustfiles/

api.py

website.py

requirements.txt

FastHttpUser

从上篇文章可以知道,HttpUser 类比 User 类更常用,它的 client 属性是 HttpSession 类(requests.Session 子类)的一个实例,可以使用 requests 发 HTTP 请求:

## 使用HttpUser
from locust import HttpUser,task,constant


class MyUser(User):
    wait_time = constant(1)
    
    @task
    def my_task1(self):
        with self.client.get("https://www.baidu.com/", catch_response=True) as res:
            if res.status_code == 200:
                print("成功")
            else:
                print("失败")

但是 requests 性能是不太好的,如果要产生更高的压力,建议使用 FastHttpUser,性能可以提升 5 到 6 倍:

## 使用FastHttpUser
from locust import task, constant
from locust.contrib.fasthttp import FastHttpUser


class MyUser(FastHttpUser):
    wait_time = constant(1)

    @task
    def my_task(self):
        with self.client.get("https://www.baidu.com/", catch_response=True) as response:
            if response.status_code == 200:
                print("成功")
            else:
                print("失败")

由于它们的 API 不一样,都有各自的适用场景,所以 FastHttpUser 不能完全替代 HttpUser。

小结

本文严格来说是上篇文章《locustfile 中的 User 类和 HttpUser 类》的下篇,介绍了核心技术 Tasks 和 Events,并给出了官方推荐的项目结构,最后介绍了比 HttpUser 性能更好的 FastHttpUser,如果想要更多的并发,可以考虑使用后者。经过这两篇文章的学习,已经可以开始动手实践使用 Locust 进行性能测试了。如果使用 locust 命令启动后,无法打开网页,可以试试加上参数:locust --web-host="127.0.0.1"。

参考资料:

https://zhuanlan.zhihu.com/p/118470760

https://docs.locust.io/en/stable/writing-a-locustfile.html#tasks

https://www.axihe.com/tools/locust/increase-performance.html

https://blog.csdn.net/u012002125/article/details/113363768