这篇大部分就是对locust官网原文的翻译和总结了,例子的一部分也是拷的原文中的。英语好的就看看粗体部分就行了,粗体部分是我自己踩的坑,其他的尽可以去看原文:
https://docs.locust.io/en/stable/writing-a-locustfile.html
Locustfile的5个类如下:
1.Userclass
一个用户类代表一类用户,每个实例代表一个被模拟的用户。可以定义一些公共属性。主要包括一下6种属性:
(1)wait_time attribute
不设置的话每个任务之间连续进行。分为
constant 在固定的时间内是常数
between 介于最小值和最大值之间的随机时间
constant_throughput用于确保任务每秒(最多)运行X次的自适应时间。
constant_tempo为自适应时间,确保任务(最多)每X秒运行一次(它是constant_throughput的数学倒数)。
(2)weight and fixed count attributes
weight 各任务之间的权重比
fixed count 固定执行次数
weight 、fixed count 和locust启动页面的Number of users一起考虑的时候会比较混乱。
我直接说下结论吧。1.当Number of users大于等于程序中的各个user中的fixed count之和时,生成的用户数就是各user的fixed count。2. 当Number of users小于程序中的各个user中的fixed count之和时, fixed count基本等于weight,生成的用户比例基本是按照fixed count的比例生成的。
比如下面这段代码:
from locust import User, task, constant
import logging as log
import datetime
import sre_constants
class TestUser1(User):
fixed_count = 30
wait_time = constant(5)
@task
def user1_task1(self):
log.info("the user1 task1 complete!!!")
log.info(datetime.datetime.now())
@task
def user1_task2(self):
log.info("the user1 task2 complete!!!")
log.info(datetime.datetime.now())
class TestUser2(User):
fixed_count = 50
wait_time = constant(10)
@task
def user2_task1(self):
log.info("the user2 task1 complete!!!")
log.info(datetime.datetime.now())
@task
def user2_task2(self):
log.info("the user2 task2 complete!!!")
log.info(datetime.datetime.now())
上面的例子中,fixed_count的和是30+50=80.
当启动数量为300的时候,启动数量就是80个。
当启动数量为26的时候。
(3)host attribute
等同于启动命令中的–host选项
(4)tasks attribute
定义在注解@task下
(5)environment attribute
暂时没想明白这个能干啥用,有用到的时候后续再补吧。
(6)on_start and on_stop methods
一个用户将在它开始运行时调用它的on_start方法,在它停止运行时调用它的on_stop方法。 对于TaskSet,当模拟用户开始执行该TaskSet时调用on_start方法,当模拟用户停止执行该TaskSet(当interrupt()被调用或用户被杀死时)时调用on_stop方法。
2.tasks
tasks有3种调用方法。
(1)最初的调用方法,@task注解,也是最常见的形式。与user的属性不同,task只能在括号中指定权重,而不能指定fixed_count,因为locust每次只从user中随机选择一个任务去执行。所以fixed_count没有意义。
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
(2)通过tasks属性调用。把任务集视为一个list。
from locust import User, constant
def my_task(user):
pass
class MyUser(User):
tasks = [my_task]
wait_time = constant(1)
与此同时,任务集也可以被视为一个字典,任务作为key,而调用的权重作为value
比如
{my_task: 3, another_task: 1}
my_task被调用3次,而其他任务只被调用1次。在内部,上面的字典实际上会被扩展成一个列表(任务属性也被更新了),
看起来像这样:
[my_task, my_task, my_task, another_task]
(3)tag注解,也就是标签。指定每个任务是哪个标签,
from locust import User, constant, task, tag
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
然后在locust启动的时候通过–tags指定启动哪些标签,或者
–exclude-tags指定哪些标签不执行。
做一个最简单的实验,可以看出来locust每次确实是随机调用一个用户的一个task,用户的调用比例基本是按照权重来的就是1:1,任务就是随机的,调用次数可能会差一些。
代码如下,最简单的:
from locust import User, task
import logging as log
class TestUser1(User):
@task
def user1_task1(self):
log.info("the user1 task1 complete!!!")
@task
def user1_task2(self):
log.info("the user1 task2 complete!!!")
class TestUser2(User):
@task
def user2_task1(self):
log.info("the user2 task1 complete!!!")
@task
def user2_task2(self):
log.info("the user2 task2 complete!!!")
生成用户的情况
任务执行结果如下所示:
user1task1:24603
user1task2:24161
user2task1:24357
user2task2:24389
3.events
简单的测试用不到这个内容,这个放到下一篇和钩子函数一起说。
4.httpuser以及其他的通讯协议。
(1)注意:由于python是可以引用其他包的,所以当使用其他通讯协议的时候可以直接引入其他协议的包,然后仍然调用
user和task两个类去建立压力测试的模板,把其他协议的代码放到@task下即可。例如下面这样。
import socket
from locust import User, TaskSet, task
import time
详细的讲解推荐https://www.cnblogs.com/jumping0709/p/15687877.html这篇。
(2)client attribute / HttpSession
包含所有的HTTP方法: get, post, put, …
具体的调用方式见
https://docs.locust.io/en/stable/api.html#locust.clients.HttpSession
(3)Validating responses
可以将返回置为失败,或者抛出一个异常。??这个后续还需要实验一下看看应用场景。
with self.client.get("/", catch_response=True) as response:
if response.text != "Success":
response.failure("Got wrong response")
elif response.elapsed.total_seconds() > 0.5:
response.failure("Request took too long")
5.Tasksets
官方文档中注明此特性不常用。更建议在user中定义task,并且用循环和逻辑去进行控制。
taskset某些场景下还是有用的。比如我们模拟几种不同的用户习惯的时候,可以把每种用户习惯定义为一个tasksets。
asksets含有有序SequentialTaskSet class,并且可以使用tag属性。
并且一定要在最后调用self.interrupt()关闭进程。
官方给的例子如下所示:
from locust import User, TaskSet, constant
class ForumSection(TaskSet):
wait_time = constant(1)
@task(10)
def view_thread(self):
pass
@task
def create_thread(self):
pass
@task
def stop(self):
self.interrupt()
class LoggedInUser(User):
wait_time = constant(5)
tasks = {ForumSection:2}
@task
def my_task(self):
pass
``
6.测试代码的结构
单个locust文件结构
common/
init.py
auth.py
config.py
locustfile.py
requirements.txt
当含有多个locust文件时,需要将多个locust文件放入一个单独的文件夹中。
common/
init.py
auth.py
config.py
my_locustfiles/
api.py
website.py
requirements.txt