Locust 类和方法
写 locustfile 文件
locustfile 是普通的 python 文件。唯一的要求是它声明至少一个从 Locust 类 继承的类(我们称其为 Locust
类)。
Locust 类
一个locust
类代表一个用户(或者代表一群蝗虫,如果有的话);
locust 将为每个正在模拟的用户生成 locust 类的一个实例。
locust 类通常应定义一些属性。
task_set
属性
该 task_set 属性应该指向一个 TaskSet 定义用户行为的类,下面将对其进行详细描述。
min_wait
和max_wait
属性
除了 task_set 属性之外,通常还需要声明 min_wait 和 max_wait 属性。
这些分别是模拟用户将在执行每个任务之间等待的最短时间和最长时间(以毫秒为单位)。
min_wait 和 max_wait 的默认值为 1000,因此,如果未声明 min_wait 和 max_wait,则 locust 将在每个任务之间始终等待 1 秒。
使用以下 locustfile,每个用户将在任务之间等待 5 到 15 秒:
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
@task
def my_task(self):
print("executing my_task")
class MyLocust(Locust):
task_set = MyTaskSet
min_wait = 5000
max_wait = 15000
该 min_wait 和 max_wait 属性也可以被覆盖在使用 taskset 类。
weight 属性
如果文件中存在多个 locust 类,并且在命令行上未指定 locust;
则每个新的实例都会从现有 locust 类中随机选择。
如果不想这么做,您可以从同一文件中指定要使用的 locust;
如下所示:
$ locust -f locust_file.py WebUserLocust MobileUserLocust
如果希望让某个 locust 类经常被执行,可以在这些类上设置一个 weight 属性。
举例来说,PC 浏览用户的可能性是手机端用户的三倍,可以像下面这种设置:
class WebUserLocust(Locust):
weight = 3
...
class MobileUserLocust(Locust):
weight = 1
...
host 属性
host 属性是要加载的域名(URL 前缀,即https://www.axihe.com/
)。
通常,--host
在 locust 启动时,使用选项在命令行上指定该选项。
如果在蝗虫类中声明了 host 属性,则 --host
在命令行上未指定 no 时将使用该属性。
TaskSet 类
如果 locust 类代表蝗虫群,那么 TaskSet 类就是这些蝗虫的大脑。
每个蝗虫类必须具有一个 task_set
属性集,该属性指向 TaskSet。
顾名思义,TaskSet 是任务的集合。
这些任务是 python 可调用对象,并且,如果我们正在对拍卖网站进行负载测试,则可以完成诸如"加载起始页",“搜索某些产品"和"竞标"之类看起来像真正用户在操作的事情,这种测试出来的结果会更加的精确,我觉得这一点还是非常值得为 locust 点赞的。
启动负载测试时,产生的 Locust 类的每个实例将开始执行其 TaskSet。
然后,发生的情况是每个 TaskSet 将选择其任务之一并调用它。
然后它将等待 N 毫秒,N 毫秒是在 Locust 类的 min_wait 和 max_wait 属性之间随机选择的(除非在 TaskSet 中直接定义了 min_wait / max_wait,在这种情况下,它将使用自己设置的属性值代替全局属性)。
然后它将再次选择要调用的新任务,再次等待,依此类推,这样循环的执行。
声明任务
为 TaskSet 声明任务以使用task
装饰器的典型方式。
这是一个例子:
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
@task
def my_task(self):
print("Locust instance (%r) executing my_task" % (self.locust))
class MyLocust(Locust):
task_set = MyTaskSet
@task
采用可选的 weight 参数,该参数可用于指定任务的执行率。
在以下示例中,task2 的执行量是 task1 的两倍:
from locust import Locust, TaskSet, task
class MyTaskSet(TaskSet):
min_wait = 5000
max_wait = 15000
@task(3)
def task1(self):
pass
@task(6)
def task2(self):
pass
class MyLocust(Locust):
task_set = MyTaskSet
tasks 属性
使用@task
装饰器声明任务是一种便利,通常是执行任务的最佳方法。
但是,也可以通过设置 tasks
属性来定义 TaskSet
的任务 (使用 @task
装饰器实际上只是填充 task 属性)。
tasks 的属性可以是一个可调用的 python 列表,或者一个调用的的字典。
tasks 是 python 可调用函数,它们接收一个参数—正在执行任务的 TaskSet 类实例。
下面这个 locustfile 的非常简单的示例(该 locustfile 实际上不会对任何内容进行负载测试):
from locust import Locust, TaskSet
def my_task(l):
pass
class MyTaskSet(TaskSet):
tasks = [my_task]
class MyLocust(Locust):
task_set = MyTaskSet
如果将tasks
属性指定为列表,则每次执行任务时,都会从 tasks 属性中随机选择它。
但是,如果任务是字典,将可调用项作为键,用一个整数作为值,则会将随机选择要执行的任务,并且让它保持你设置的比例。
因此,执行如下任务:
{my_task: 3, another_task: 1}
my_task
的执行可能性是another_task
的 3 倍。
TaskSets 可以被嵌套
TaskSet 的一个非常重要的特性是它们可以嵌套着往下写,因为在我们真正浏览网站的时候;通常是一级一级的往下点,可能也会点二级目录下的文章之类的。
因此,TaskSets
做了能够定义一种行为,以便更模拟真实用户的事情。
例如,我们可以使用以下结构定义 TaskSet:
- 主要用户行为
阿西河网站首页
阿西河论坛页面
- 读线程
- 回帖
- 新线程
- 查看下一页
浏览教程分类
- 看测试教程
- 筛选测试教程
关于本站页面
嵌套 TaskSet 的方式就像使用 task 属性指定任务时一样,但是不是引用 python 函数,而是引用另一个 TaskSet:
class ForumPage(TaskSet):
@task(20)
def read_thread(self):
pass
@task(1)
def new_thread(self):
pass
@task(5)
def stop(self):
self.interrupt()
class UserBehaviour(TaskSet):
tasks = {ForumPage:10}
@task
def index(self):
pass
因此,在上面的示例中,如果在执行 UserBehaviour TaskSet 时选择了要执行的 ForumPage ,则 ForumPage TaskSet 将开始执行。然后,ForumPage TaskSet 将选择其自己的任务之一,执行它,等待,依此类推。
关于上述示例,需要注意一件事,那就是在 ForumPage 的 stop 方法中对 self.interrupt()
的调用。
这实际上是要停止执行 ForumPage 任务集,并且该执行将在 UserBehaviour 实例中继续。
如果我们没有在 ForumPage 的某个地方调用interrupt()
方法;则一旦启动,Locust 将永远不会停止运行 ForumPage 任务。
但是通过具有中断功能,我们可以与任务权重一起定义用户以什么方式离开论坛。
也可以使用 @task
装饰器在类中内联声明一个嵌套的 TaskSet, 就像声明普通任务时一样:
class MyTaskSet(TaskSet):
@task
class SubTaskSet(TaskSet):
@task
def my_task(self):
pass
引用 Locust 实例或父级 TaskSet 实例
TaskSet 实例的属性 locust 指向其 Locust 实例,而该属性 parent 指向其父 TaskSet(在 TaskSet 中,它将指向 Locust 实例)。
TaskSequence 类
TaskSequence 类是 TaskSet,但其任务将按顺序执行。
要定义此顺序,您应该执行以下操作:
class MyTaskSequence(TaskSequence):
@seq_task(1)
def first_task(self):
pass
@seq_task(2)
def second_task(self):
pass
@seq_task(3)
@task(10)
def third_task(self):
pass
在上面的示例中,顺序被定义为执行 first_task ,然后执行 second_task ,最后执行 10 次Third_task 。
如您所见,您可以把 @task
装饰器 和 @seq_task
一起组合使用,当然也可以将 TaskSet 嵌套在 TaskSequences 中,反过来一样的。
setup / teardown / on_start
/ on_stop
Locust optionally supports Locust
level setup
and teardown
, TaskSet
level setup
and teardown
, and TaskSet
on_start
and on_stop
setup
和 teardown
setup
和 teardown
(无论是在 Locust
还是 TaskSet
上运行)都是只能运行一次的方法。
在任务开始运行之前运行setup
,而在所有任务完成并且蝗虫退出后运行 teardown
;
这使您能够在任务开始运行之前做一些准备工作(比如创建数据库,或者打个日志装 X 等等),并在蝗虫退出之前进行清理(例如删库跑路)。
使用时,只需在 Locust
或 TaskSet
类上声明 setup
teardown
就可以了;
on_start
和 on_stop
方法
一个 TaskSet 类可以声明 on_start 方法或 on_stop 方法,
当模拟用户开始执行该 TaskSet 类时,将调用 on_start
方法;
而当 TaskSet 停止时,将调用 on_stop <locust.core.TaskSet.on_stop()
方法。
事件顺序
由于许多设置和清除操作是相互依赖的,因此以下是它们的运行顺序:
- Locust setup
- TaskSet setup
- TaskSet on_start
- TaskSet tasks…
- TaskSet on_stop
- TaskSet teardown
- Locust teardown
通常, setup
and teardown
方法应该是对应的,最好是一对使用。
安全模式
HTTP 客户端配置为以 safe_mode
运行。 这是因为由于连接错误,超时或类似原因而失败的任何请求都不会引发异常,而是返回一个空的虚拟 Response 对象。
该请求将在 Locust
的统计信息中报告为失败。
返回的虚拟 Response
的 content
属性将设置为 None
,其 status_code
将为 0
。