大部分是从官方文档翻译和总结过来的,只进行过简单实践。
Locust 的安装
根据官方文档(https://docs.locust.io/en/stable/index.html),安装步骤非常简单:
$ pip3 install locust
安装完成时,发现没有 locust
命令,翻看 wiki,找到解决方案:
// 在执行 pip 安装时,出现了一些 Warning 信息:
WARNING: The script flask is installed in '/home/coffee/.local/bin' which is not on PATH.
Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
// 把信息中的路径添加到 PATH 里就可以了:
$ export PATH=$PATH:/home/coffee/.local/bin
// 执行 locust 命令,验证是否安装好了。输出如下,就可以用了:
$ locust -V
locust 1.4.1
Locust 的使用
locust 文件其实是一个 python 模块,它可以被 import 到 python 文件中。
查看 locust 命令的 help 信息,看看都有什么吧:
$ locust -h
Usage: locust [OPTIONS] [UserClass ...]
Common options:
-h, --help show this help message and exit
-f LOCUSTFILE, --locustfile LOCUSTFILE
Python module file to import, e.g. '../other.py'. Default: locustfile
--config CONFIG Config file path
-H HOST, --host HOST Host to load test in the following format: http://10.21.32.33
-u NUM_USERS, --users NUM_USERS
Number of concurrent Locust users. Primarily used together with --headless. Can be changed during a test by inputs w, W(spawn 1, 10 users) and s, S(stop 1, 10 users)
-r SPAWN_RATE, --spawn-rate SPAWN_RATE
The rate per second in which users are spawned. Primarily used together with --headless
-t RUN_TIME, --run-time RUN_TIME
Stop after the specified amount of time, e.g. (300s, 20m, 3h, 1h30m, etc.). Only used together with --headless. Defaults to run forever.
-l, --list Show list of possible User classes and exit
Web UI options:
--web-host WEB_HOST Host to bind the web interface to. Defaults to '*' (all interfaces)
--web-port WEB_PORT, -P WEB_PORT
Port on which to run web host
--headless Disable the web interface, and instead start the load test immediately. Requires -u and -t to be specified.
--web-auth WEB_AUTH Turn on Basic Auth for the web interface. Should be supplied in the following format: username:password
--tls-cert TLS_CERT Optional path to TLS certificate to use to serve over HTTPS
--tls-key TLS_KEY Optional path to TLS private key to use to serve over HTTPS
... ...
(内容比较多)
- -f: 指定测试文件,是必须指定的参数,测试文件是 Python 文件。
- -t: 指定测试时间,使用该参数时必须使用
--headless
参数,此时,将不会启动 GUI 模式,而是直接执行该测试(此时如果尝试打开 Locust 的网页接口,是This site can’t be reached
的。所以,还必须指定-H/--host
参数(测试文件里没有指定所测试的 URL)。默认是永远运行。 - -l: 列出测试文件中可用的用户。
- -u: 指定测试的用户数量。
如何写一个 locust 文件
locust 文件其实是一个普通的 python 文件,它唯一必须要有的内容是定义至少一个继承自 User
的类。
User 类
一个 user 类表示一个用户。在模拟测试时,Locust 会为每一个用户启动一个用户实例。User
类的一些属性如下。
wait_time 属性
两个任务之间需要等待的时间。
constant
:between
:constant_pacing
:
也可以自定义 wait_time
,比如:
class MyUser(User):
last_wait_time = 0
def wait_time(self):
self.last_wait_time += 1
return self.last_wait_time
... ...
weight 属性
如果测试文件中有多个用户,并且在命令行中没有指定使用哪个用户来执行,Locust 会为每个 User
类启动相同数量的用户。如果指定用户的话,命令行是这样子的:
$ locust -f locust_file.py WebUser MobileUser
如果对不同用户的模拟比例不一样,就需要使用 weight
属性来设置了:
class WebUser(User):
weight = 3
...
class MobileUser(User):
weight = 1
...
host 属性
即指定测试的 URL,同命令行中的 --host
参数,以及 UI 模式下的 HOST 参数。
tasks 属性
测试任务类需要用 @task
来装饰。(下面还有关于 task 的详细说明)
enviorenment 属性
比如可以在一个 task 方法中停止 ruuner:
self.environment.runner.quit()
on_start 和 on_stop 属性
在 User
(任务集 TaskSet)中可以声明 on_start
和 on_stop
方法。开始执行任务时,会调用 on_start
方法,任务执行结束时,会调用 on_stop
方法。
Task
执行压力测试时,每个模拟用户会创建 User 类的实例,运行在线程中。这些模拟的用户选择一个任务执行,等待一会儿,再执选择一个新的任务执行,如此往复。
@task 装饰器
为 User 添加任务的最简单的方式是使用 @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 的执行比率。比如在下面的例子中,task2 被选择执行的概率是 task1 的两倍:
from locust import User, task
class MyUser(User):
@task(3)
def task1(self):
pass
@task(6)
def task2(self):
pass
tasks 属性
另一个定义 User 类的任务的方法是设置 tasks
属性。
tasks
属性是一个任务列表,或者一个任务的字典 \<Task: int\>
,如:
from locust import User, constant
def my_task(user):
pass
class MyUser(User):
tasks = [my_task]
如果设置的 tasks 属性是一个列表,那么在执行时是随机选择的;如果是一个字典,仍然会随机选择执行,但会以设置的 int
值考虑权重。
# my_task 的执行概率是 another_task 的 3 倍
{my_task: 3, another_task: 1}
# 将上面的字典转换为列表,可以表示为:
[my_task, my_task, my_task, another_task]
@tag 装饰器
还可以给 task 设置 @tag
装饰器,执行 locust
命令时就可以使用--tags
或者 --exclude-tags
参数来指定所要执行的任务了。
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
执行时,如果使用参数 --tags tag1
,那么只有 task1 和 task2 被执行;如果使用参数 --tags tag2 tag3
,那么只有 task2 和 task3 被执行。
而 --exclude-tags
的效果相反(就是不包含的意思),如果使用参数 --exclude-tags tag3
,那么将会执行 task, task2, task4。
Events
test_start 和 test_stop
init
其他 events
HttpUser 类
HttpUser
是最常用的用户类,它可以添加 client
属性来发起 HTTP 请求。
from locust import HttpUser, task, between
class MyUser(HttpUser):
wait_time = between(5, 15)
@task(4)
def index(self):
self.client.get("/")
@task(1)
def about(self):
self.client.get("/about/")
client 属性/HttpSession
client
是 HttpSession
的一个实例。HttpSession
是 requests.Session
的子类,它包含了所有的 HTTP 方法:get
, post
, put
, …
用法和 HttpSession 是一样的。
response = self.client.post("/login", {"username":"testuser", "password":"secret"})
print("Response status code:", response.status_code)
print("Response text:", response.text)
response = self.client.get("/my-profile")
验证结果
可以通过 catch_response
参数及调用 response.failure()
来验证一个失败的结果。
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")
即使返回的 code 是失败的,也可以把请求标记为成功:
with self.client.get("/does_not_exist/", catch_response=True) as response:
if response.status_code == 404:
response.success()
还可以通过抛出异常来避免记录该结果,抛出一个 locust exception 即可:
from locust.exception import RescheduleTask
...
with self.client.get("/does_not_exist/", catch_response=True) as response:
if response.status_code == 404:
raise RescheduleTask()
用动态参数来发起一组请求
使用 HttpSession
的 name
参数:
# Statistics for these requests will be grouped under: /blog/?id=[id]
for i in range(10):
self.client.get("/blog?id=%i" % i, name="/blog?id=[id]")
HTTP 代理设置
为了提高性能,Locust 将 HttpSession 的 trust_env
设置为 False
,以关闭代理。如要开启,将 locust_instance.client.trust_env
设置为 True
。
任务集
如何组织测试代码?
对于小型测试,把测试内容写到单独的一个 locustfile.py
即可。但对于大的测试项目,需要把测试代码放到不同的测试文件和目录中,遵循 Python 的最佳实践就可以了。比如:
- Project root
common/
__init__.py
auth.py
config.py
locustfile.py
requirements.txt
再复杂点的可能是这样:
- Project root
common/
__init__.py
auth.py
config.py
locustfiles/
api.py
website.py
requirements.txt
Locust 的配置文件
可以将一些测试配置写入配置文件(如:locust.conf
),就不需要命令行的参数来完成了。如:
locustfile = test.py
host = http://www.example.com
headless = true
users = 10
spawn-rate = 2
run-time = 30s
执行命令时可以这样:
$ locust --config=locust.conf
该配置将进入非 GUI 模式。
如果不指定 headless
和 run-time
,则进入 GUI 模式。