Locust 性能测试工具安装使用说明

2023-07-12,,

1. 介绍

    它是一个开源性能测试工具。使用 Python 代码来定义用户行为。用它可以模拟百万计的并发用户访问你的系统。

性能工具对比


LoadRunner 是非常有名的商业性能测试工具,功能非常强大。使用也比较复杂,目前大多介绍性能测试的书籍都以该工具为基础,甚至有些书整本都在介绍 LoadRunner 的使用。

Jmeter 同样是非常有名的开源性能测试工具,功能也很完善,在本书中介绍了它作为接口测试工具的使用。但实际上,它是一个标准的性能测试工具。关于Jmeter相关的资料也非常丰富,它的官方文档也很完善。

Locust 同样是性能测试工具,虽然官方这样来描述它 “An open source load testing tool.” 。但其它和前面两个工具有着较大的不同。相比前面两个工具,功能上要差上不少,但它也并非优点全无。

Locust 完全基本 Python 编程语言,采用 Pure Python 描述测试脚本,并且 HTTP 请求完全基于 Requests 库。除了 HTTP/HTTPS 协议,Locust 也可以测试其它协议的系统,只需要采用Python调用对应的库进行请求描述即可。
LoadRunner 和 Jmeter 这类采用进程和线程的测试工具,都很难在单机上模拟出较高的并发压力。Locust 的并发机制摒弃了进程和线程,采用协程(gevent)的机制。协程避免了系统级资源调度,由此可以大幅提高单机的并发能力。

正是基于这样的特点,使我选择使用Locust工具来做性能测试,另外一个原因是它可以让我们换一种方式认识性能测试,可能更容易看清性能测试的本质。

我想已经成功的引起了你的兴趣,那么接下来就跟着来学习Locust的使用吧。

2. Locust 安装

Locust 是基于 Python 语言的一个性能测试库,如果要想使用它来做性能测试必须要先安装 Python 。
python3.6 版本安装(略)

方式一:通过 pip 命令安装

 
 
 

1

 
 

 

1

pip install  locust

 
 

方式二:GitHub下载安装

GitHub项目地址:https://github.com/locustio/locust/

将项目克隆下来,通过Python 执行 setup.py 文件

 
 
 

1

 
 

 

1

python setup.py install

 
 

最后,检查是否安装成功。命令窗口,输入 “locust --v” 查看版本

3. Locust 使用入门

编写第一个性能测试脚本

创建一个locustfile.py 脚本文件

 
 
 

13

 
 

 

1

from locust import HttpLocust, TaskSet, task

2


3

# 定义用户行为

4

class UserBehavior(TaskSet):

5


6

    @task

7

    def baidu_index(self):

8

        self.client.get("/")

9


10

class WebsiteUser(HttpLocust):

11

    task_set = UserBehavior

12

    min_wait = 3000

13

    max_wait = 6000

 
 

UserBehavior类继承TaskSet类,用于描述用户行为。
baidu_index() 方法表示一个用户为行,访问百度首页。
使用@task装饰该方法为一个事务。client.get()用于指请求的路径“/”,因为是百度首页,所以指定为根路径。

WebsiteUser类用于设置性能测试。

task_set :指向一个定义的用户行为类。
min_wait :执行事务之间用户等待时间的下界(单位:毫秒)。
max_wait :执行事务之间用户等待时间的上界(单位:毫秒)。

执行性能测试脚本

 
 
 

3

 
 

 

1

locust -f ./locustfile.py --host=https://www.baidu.com

2

#[2019-07-04 15:40:11,348] tsbc.leaptocloud/INFO/locust.main: Starting web monitor at *:8089

3

#[2019-07-04 15:40:11,348] tsbc.leaptocloud/INFO/locust.main: Starting Locust 0.11.1

 
 

-f 指定性能测试脚本文件。
--host 指定被测试应用的URL的地址,注意访问百度使用的HTTPS协议。

通过浏览器访问:http://127.0.0.1:8089(Locust启动网络监控器,默认为端口号为: 8089)

设置模拟用户数。

设置孵化率 每秒产生(启动)的虚拟用户数。

点击 “启动” 按钮,开始运行性能测试。

性能测试参数分析

Type: 请求的类型,例如GET/POST。
Name:请求的路径。这里为百度首页,即:https://www.baidu.com/
request:当前请求的数量。
fails:当前请求失败的数量。
Median:中间值,单位毫秒,一半的服务器响应时间低于该值,而另一半高于该值。
Average:平均值,单位毫秒,所有请求的平均响应时间。
Min:请求的最小服务器响应时间,单位毫秒。
Max:请求的最大服务器响应时间,单位毫秒。
Content Size:单个请求的大小,单位字节。

4. Locust 脚本开发进阶

Locust 中类的定义和使用

HttpLocust 类

Locust类中,具有一个client属性,它对应着虚拟用户作为客户端所具备的请求能力,也就是我们常说的请求方法。通常情况下,我们不会直接使用Locust类,因为其client属性没有绑定任何方法。因此在使用Locust时,需要先继承Locust类,然后在继承子类中的client属性中绑定客户端的实现类。

对于常见的HTTP(S)协议,Locust已经实现了HttpLocust类,其client属性绑定了HttpSession类,而HttpSession又继承自requests.Session。因此在测试HTTP(S)Locust脚本中,我们可以通过client属性来使用Python requests库的所有方法,包括GET/POST/HEAD/PUT/DELETE/PATCH等,调用方式也与requests完全一致。另外,由于requests.Session的使用,因此client的方法调用之间就自动具有了状态记忆的功能。常见的场景就是,在登录系统后可以维持登录状态的Session,从而后续HTTP请求操作都能带上登录态。

而对于HTTP(S)以外的协议,我们同样可以使用Locust进行测试,只是需要我们自行实现客户端。在客户端的具体实现上,可通过注册事件的方式,在请求成功时触发events.request_success,在请求失败时触发events.request_failure即可。然后创建一个继承自Locust类的类,对其设置一个client属性并与我们实现的客户端进行绑定。后续,我们就可以像使用HttpLocust类一样,测试其它协议类型的系统。

Locust类中,除了client属性,还有几个属性需要关注下:

task_set: 指向一个TaskSet类,TaskSet类定义了用户的任务信息,该属性为必填;
max_wait/min_wait: 每个用户执行两个任务间隔时间的上下限(毫秒),具体数值在上下限中随机取值,若不指定则默认间隔时间固定为1秒;
host:被测系统的host,当在终端中启动locust时没有指定--host参数时才会用到;
weight:同时运行多个Locust类时会用到,用于控制不同类型任务的执行权重。

测试开始后,每个虚拟用户(Locust实例)的运行逻辑都会遵循如下规律:

    先执行WebsiteTasks中的on_start(只执行一次),作为初始化;
    WebsiteTasks中随机挑选(如果定义了任务间的权重关系,那么就是按照权重关系随机挑选)一个任务执行;
    根据Locust类min_waitmax_wait定义的间隔时间范围(如果TaskSet类中也定义了min_wait或者max_wait,以TaskSet中的优先),在时间范围中随机取一个值,休眠等待;
    重复2~3步骤,直至测试任务终止。

 
 
 

20

 
 

 

1

from locust import HttpLocust, TaskSet, task

2


3

class UserTask(TaskSet):

4


5

    @task

6

    def tc_index(self):

7

        self.client.get("/")

8


9

class UserOne(HttpLocust):

10

    task_set = UserTask

11

    weight = 1

12

    min_wait = 1000

13

    max_wait = 3000

14

    stop_timeout = 5

15

    host = "https://www.baidu.com"

16


17

class UserTwo(HttpLocust):

18

    weight = 2

19

    task_set = UserTask

20

    host = "https://www.baidu.com"

 
 

一个Locust实例被挑选执行的权重,数值越大,执行频率越高。在一个 locustfile.py 文件中可以同时定义多个 HttpLocust 子类,然后分配他们的执行权重,例如:

然后在终端启动测试:

locust -f locustfile.py UserOne UserTwo

 
 
 

1

 
 

 

1

locust -f locustfile.py UserOne UserTwo

 
 

TaskSet 类

性能测试工具要模拟用户的业务操作,就需要通过脚本模拟用户的行为。在前面的比喻中说到,TaskSet类好比蝗虫的大脑,控制着蝗虫的具体行为。

具体地,TaskSet类实现了虚拟用户所执行任务的调度算法,包括规划任务执行顺序(schedule_task)、挑选下一个任务(execute_next_task)、执行任务(execute_task)、休眠等待(wait)、中断控制(interrupt)等等。在此基础上,我们就可以在TaskSet子类中采用非常简洁的方式来描述虚拟用户的业务测试场景,对虚拟用户的所有行为(任务)进行组织和描述,并可以对不同任务的权重进行配置。

TaskSet子类中定义任务信息时,可以采取两种方式,@task装饰器tasks属性

采用@task装饰器定义任务信息时,描述形式如下:

from locust import TaskSet, task
class UserBehavior(TaskSet):
@task(1)
def test_job1(self):
self.client.get('/job1')
@task(2)
def test_job2(self):
self.client.get('/job2')

 
 
 

8

 
 

 

1

from locust import TaskSet, task

2

class UserBehavior(TaskSet):

3

    @task(1)

4

    def test_job1(self):

5

        self.client.get('/job1')

6

    @task(2)

7

    def test_job2(self):

8

        self.client.get('/job2')

 
 

采用tasks属性定义任务信息时,描述形式如下:
from locust import TaskSet
def test_job1(obj):
obj.client.get('/job1')
def test_job2(obj):
obj.client.get('/job2')
class UserBehavior(TaskSet):
tasks = {test_job1:1, test_job2:2}
# tasks = [(test_job1,1), (test_job1,2)] # 两种方式等价

 
 
 

8

 
 

 

1

from locust import TaskSet

2

def test_job1(obj):

3

    obj.client.get('/job1')

4

def test_job2(obj):

5

    obj.client.get('/job2')

6

class UserBehavior(TaskSet):

7

    tasks = {test_job1:1, test_job2:2}

8

    # tasks = [(test_job1,1), (test_job1,2)] # 两种方式等价

 
 

在如上两种定义任务信息的方式中,均设置了权重属性,即执行test_job2的频率是test_job1的两倍。
若不指定执行任务的权重,则相当于比例为1:1
A:
from locust import TaskSet, task
class UserBehavior(TaskSet):
@task
def test_job1(self):
self.client.get('/job1')
@task
def test_job2(self):
self.client.get('/job2')

 
 
 

8

 
 

 

1

from locust import TaskSet, task

2

class UserBehavior(TaskSet):

3

    @task

4

    def test_job1(self):

5

        self.client.get('/job1')

6

    @task

7

    def test_job2(self):

8

        self.client.get('/job2')

 
 

B:
from locust import TaskSet
def test_job1(obj):
obj.client.get('/job1')
def test_job2(obj):
obj.client.get('/job2')
class UserBehavior(TaskSet):
tasks = [test_job1, test_job2]

 
 
 

7

 
 

 

1

from locust import TaskSet

2

def test_job1(obj):

3

    obj.client.get('/job1')

4

def test_job2(obj):

5

    obj.client.get('/job2')

6

class UserBehavior(TaskSet):

7

    tasks = [test_job1, test_job2]

 
 

在TaskSet子类中除了定义任务信息,还有一个是经常用到的,那就是on_start函数。这个和LoadRunner中的vuser_init功能相同,在正式执行测试前执行一次,主要用于完成一些初始化的工作。例如,当测试某个搜索功能,而该搜索功能又要求必须为登录态的时候,就可以先在on_start中进行登录操作HttpLocust使用到了requests.Session,因此后续所有任务执行过程中就都具有登录态了。

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

 
 
 

13

 
 

 

1

class MyTaskSequence(TaskSequence):

2

    @seq_task(1)

3

    def first_task(self):

4

        pass

5


6

    @seq_task(2)

7

    def second_task(self):

8

        pass

9


10

    @seq_task(3)

11

    @task(10)

12

    def third_task(self):

13

        pass

 
 

在上面的示例中,顺序被定义为执行first_task,然后执行second_task,最后执行third_task 10次。如您所见,您可以@seq_task使用@task装饰器进行组合,当然您也可以在TaskSequences中嵌套TaskSet,反之亦然。

公共库

子目录可以是一种更清晰的方法(参见下面的示例),但是locust只会导入相对于放置运行的locustfile的目录的模块。如果您希望从项目根目录(即运行locust命令的位置)导入,请确保sys.path.append(os.getcwd())在导入任何公共库之前写入您的locust文件 - 这将使项目成为root(即当前正在工作)目录)可导入。
项目根

__init__.py
common/
__init__.py
config.py
auth.py
locustfiles/
__init__.py
web_app.py
api.py
ecommerce.py

使用上述项目结构,您的locust文件可以使用以下命令导入公共库:
sys.path.append(os.getcwd())
import common.auth

 
 
 

2

 
 

 

1

sys.path.append(os.getcwd())

2

import common.auth

 
 

HttpSession类

用于在请求之间执行Web请求和保留(会话)cookie的类(以便能够登录和退出网站)。记录每个请求,以便蝗虫可以显示统计信息。

每个发出请求的方法还需要两个额外的可选参数,这些参数是特定于Locust的,并且在python-requests中不存在。这些是:

name - (可选)可以指定在Locust的统计信息中用作标签而不是URL路径的参数。这可用于将请求的不同URL分组到Locust统计信息中的单个条目中。
catch_response - (可选)布尔参数,如果设置,可用于发出请求,返回上下文管理器作为with语句的参数。这将允许根据响应内容将请求标记为失败,即使响应代码正常(2xx)。相反也有效,可以使用catch_response来捕获请求,然后将其标记为成功,即使响应代码不是(即500或404)。

request方法网址名称=无catch_response = False** kwargs 

构造并发送一个requests.Request。返回requests.Response对象。

参数: 方法 - 新Request对象的方法。
url - 新Request对象的URL 。
name - (可选)可以指定在Locust的统计信息中用作标签而不是URL路径的参数。这可用于将请求的不同URL分组到Locust统计信息中的单个条目中。
catch_response - (可选)布尔参数,如果设置,可用于发出请求,返回上下文管理器作为with语句的参数。这将允许根据响应内容将请求标记为失败,即使响应代码正常(2xx)。相反也有效,可以使用catch_response来捕获请求,然后将其标记为成功,即使响应代码不是(即500或404)。
params - (可选)要在查询字符串中发送的字典或字节Request
data - (可选)在体内发送的字典或字节Request
headers - (可选)用于发送的HTTP头的字典Request
cookies - (可选)用于发送的Dict或CookieJar对象Request
files - (可选)用于多部分编码上载的字典。'filename': file-like-objects
auth - (可选)Auth tuple或callable以启用Basic / Digest / Custom HTTP Auth。
timeoutfloat tuple) - (可选)等待服务器在放弃之前以浮点或(连接超时,读取超时)元组的形式发送数据的时间长度。
allow_redirectsbool) - (可选)默认设置为True。
proxies - (可选)字典映射协议到代理的URL。
stream - (可选)是否立即下载响应内容。默认为False
验证 - (可选)是否True,将验证SSL证书。还可以提供CA_BUNDLE路径。
cert - (可选)if String,ssl客户端证书文件(.pem)的路径。如果Tuple,('cert','key')配对。

脚本增强

设置响应断言

性能测试也需要设置断言么? 某些情况下是需要,比如你在请求一个页面时,就可以通过状态来判断返回的 HTTP 状态码是不是 200。

 
 
 

17

 
 

 

1

from locust import HttpLocust, TaskSet, task

2


3

class UserTask(TaskSet):

4


5

    @task

6

    def job(self):

7

        with self.client.get('/', catch_response = True) as response:

8

            if response.status_code == 200:

9

                response.failure('Failed!')

10

            else:

11

                response.success()

12


13

class User(HttpLocust):

14

    task_set = UserTask

15

    min_wait = 1000

16

    max_wait = 3000

17

    host = "https://www.baidu.com"

 
 

catch_response = True :布尔类型,如果设置为 True, 允许该请求被标记为失败。

通过 client.get() 方法发送请求,将整个请求的给 response, 通过 response.status_code 得请求响应的 HTTP 状态码。如果不为 200 则通过 response.failure('Failed!') 打印失败!

Locust关联

在某些请求中,需要携带之前从Server端返回的参数,因此在构造请求时需要先从之前的Response中提取出所需的参数。

 
 
 

24

 
 

 

1

from lxml import etree

2

from locust import TaskSet, task, HttpLocust

3

class UserBehavior(TaskSet):

4

    @staticmethod

5

    def get_session(html):

6

        tree = etree.HTML(html)

7

        return tree.xpath("//div[@class='btnbox']/input[@name='session']/@value")[0]

8

    @task(10)

9

    def test_login(self):

10

        html = self.client.get('/login').text

11

        username = 'user@compay.com'

12

        password = '123456'

13

        session = self.get_session(html)

14

        payload = {

15

            'username': username,

16

            'password': password,

17

            'session': session

18

        }

19

        self.client.post('/login', data=payload)

20

class WebsiteUser(HttpLocust):

21

    host = 'http://debugtalk.com'

22

    task_set = UserBehavior

23

    min_wait = 1000

24

    max_wait = 3000

 
 

Locust 参数化

所有并发虚拟用户共享同一份测试数据,并且保证虚拟用户使用的数据不重复。
例如,模拟3用户并发注册账号,要求注册账号不重复,注册完毕后结束测试;

 
 
 

31

 
 

 

1

from locust import TaskSet, task, HttpLocust

2

import queue

3

class UserBehavior(TaskSet):

4

    @task

5

    def test_register(self):

6

        try:

7

            data = self.locust.user_data_queue.get()

8

        except queue.Empty:

9

            print('account data run out, test ended.')

10

            exit(0)

11

        print('register with user: {}, pwd: {}'\

12

            .format(data['username'], data['password']))

13

        payload = {

14

            'username': data['username'],

15

            'password': data['password']

16

        }

17

        self.client.post('/register', data=payload)

18

class WebsiteUser(HttpLocust):

19

    host = 'http://debugtalk.com'

20

    task_set = UserBehavior

21

    user_data_queue = queue.Queue()

22

    for index in range(100):

23

        data = {

24

            "username": "test%04d" % index,

25

            "password": "pwd%04d" % index,

26

            "email": "test%04d@debugtalk.test" % index,

27

            "phone": "186%08d" % index,

28

        }

29

        user_data_queue.put_nowait(data)

30

    min_wait = 1000

31

    max_wait = 3000

 
 

HttpRunner使用(v2.x)

介绍

HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架,只需编写维护一份 YAML/JSON 脚本,即可实现自动化测试、性能测试、线上监控、持续集成等多种测试需求。

安装

 
 
 

1

 
 

 

1

 pip install httprunner

 
 

在 HttpRunner 安装成功后,系统中会新增如下 5 个命令:

httprunner: 核心命令
ate: 曾经用过的命令(当时框架名称为 ApiTestEngine),功能与 httprunner 完全相同
hrun: httprunner 的缩写,功能与 httprunner 完全相同
locusts: 基于 Locust 实现性能测试
har2case: 辅助工具,可将标准通用的 HAR 格式(HTTP Archive)转换为YAML/JSON格式的测试用例

httprunner、hrun、ate 三个命令完全等价,功能特性完全相同,个人推荐使用hrun命令。

运行如下命令,若正常显示版本号,则说明 HttpRunner 安装成功。

 
 
 

2

 
 

 

1

(locust) [root@tsbc api]# hrun -V

2

2.1.3

 
 

快速使用

抓包

使用Chrome或者火狐浏览器,打开要访问的API,同时使用打开开发工具【网络】,查看接口请求状态

选中接口请求,右键导出保存为HAR格式文件,假设导出的文件名称为 demo-quickstart.har。

生成测试用例

为了简化测试用例的编写工作,HttpRunner 实现了测试用例生成的功能。

首先,需要将抓取得到的数据包导出为 HAR 格式的文件,如:名称为 demo-quickstart.har。

然后,在命令行终端中运行如下命令,即可将 demo-quickstart.har 转换为 HttpRunner 的测试用例文件。

 
 
 

4

 
 

 

1

har2case docs/data/demo-quickstart.har -2y

2

INFO:root:Start to generate testcase.

3

INFO:root:dump testcase to YAML format.

4

INFO:root:Generate YAML testcase successfully: docs/data/demo-quickstart.yml

 
 

使用 har2case 转换脚本时默认转换为 JSON 格式,加上 -2y 参数后转换为 YAML 格式。两种格式完全等价,YAML 格式更简洁,JSON 格式支持的工具更丰富,大家可根据个人喜好进行选择
经过转换,在源 demo-quickstart.har 文件的同级目录下生成了相同文件名称的 YAML 格式测试用例文件 demo-quickstart.yml,其内容如下:

 
 
 

41

 
 

 

1

- config:

2

    name: testcase description

3

    variables: {}

4


5

- test:

6

    name: /api/get-token

7

    request:

8

        headers:

9

            Content-Type: application/json

10

            User-Agent: python-requests/2.18.4

11

            app_version: 2.8.6

12

            device_sn: FwgRiO7CNA50DSU

13

            os_platform: ios

14

        json:

15

            sign: 9c0c7e51c91ae963c833a4ccbab8d683c4a90c98

16

        method: POST

17

        url: http://127.0.0.1:5000/api/get-token

18

    validate:

19

        - eq: [status_code, 200]

20

        - eq: [headers.Content-Type, application/json]

21

        - eq: [content.success, true]

22

        - eq: [content.token, baNLX1zhFYP11Seb]

23


24

- test:

25

    name: /api/users/1000

26

    request:

27

        headers:

28

            Content-Type: application/json

29

            User-Agent: python-requests/2.18.4

30

            device_sn: FwgRiO7CNA50DSU

31

            token: baNLX1zhFYP11Seb

32

        json:

33

            name: user1

34

            password: '123456'

35

        method: POST

36

        url: http://127.0.0.1:5000/api/users/1000

37

    validate:

38

        - eq: [status_code, 201]

39

        - eq: [headers.Content-Type, application/json]

40

        - eq: [content.success, true]

41

        - eq: [content.msg, user created successfully.]

 
 

现在我们只需要知道如下几点:

每个 YAML/JSON 文件对应一个测试用例(testcase)
每个测试用例为一个list of dict结构,其中可能包含全局配置项(config)和若干个测试步骤(test)
config 为全局配置项,作用域为整个测试用例
test 对应单个测试步骤,作用域仅限于本身

如上便是 HttpRunner 测试用例的基本结构。

demo-quickstart.json

 
 
 

58

 
 

 

1

[

2

    {

3

        "config": {

4

            "name": "testcase description",

5

            "variables": {}

6

        }

7

    },

8

    {

9

        "test": {

10

            "name": "/api/get-token",

11

            "request": {

12

                "url": "http://127.0.0.1:5000/api/get-token",

13

                "method": "POST",

14

                "headers": {

15

                    "User-Agent": "python-requests/2.18.4",

16

                    "device_sn": "FwgRiO7CNA50DSU",

17

                    "os_platform": "ios",

18

                    "app_version": "2.8.6",

19

                    "Content-Type": "application/json"

20

                },

21

                "json": {

22

                    "sign": "9c0c7e51c91ae963c833a4ccbab8d683c4a90c98"

23

                }

24

            },

25

            "validate": [

26

                {"eq": ["status_code", 200]},

27

                {"eq": ["headers.Content-Type", "application/json"]},

28

                {"eq": ["content.success", true]},

29

                {"eq": ["content.token", "baNLX1zhFYP11Seb"]}

30

            ]

31

        }

32

    },

33

    {

34

        "test": {

35

            "name": "/api/users/1000",

36

            "request": {

37

                "url": "http://127.0.0.1:5000/api/users/1000",

38

                "method": "POST",

39

                "headers": {

40

                    "User-Agent": "python-requests/2.18.4",

41

                    "device_sn": "FwgRiO7CNA50DSU",

42

                    "token": "baNLX1zhFYP11Seb",

43

                    "Content-Type": "application/json"

44

                },

45

                "json": {

46

                    "name": "user1",

47

                    "password": "123456"

48

                }

49

            },

50

            "validate": [

51

                {"eq": ["status_code", 201]},

52

                {"eq": ["headers.Content-Type", "application/json"]},

53

                {"eq": ["content.success", true]},

54

                {"eq": ["content.msg", "user created successfully."]}

55

            ]

56

        }

57

    }

58

]

 
 

首次运行测试用例

运行测试用例的命令为hrun,后面直接指定测试用例文件的路径即可。

 
 
 

1

 
 

 

1

$ hrun docs/data/demo-quickstart-1.yml

 
 

执行性能测试使用locusts 命令执行,

 
 
 

1

 
 

 

1

locusts -f docs/data/demo-quickstart-1.yml

 
 

进阶使用参考官方文档:
https://cn.httprunner.org/
 

<!--
.wiz-editor-body .wiz-code-container{position: relative; padding:8px 0; margin: 5px 0;text-indent:0; text-align:left;}.CodeMirror {font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; color: black; font-size: 10.5pt; font-size: 0.875rem}.wiz-editor-body .wiz-code-container .CodeMirror div {margin-top: 0; margin-bottom: 0;}.CodeMirror-lines {padding: 4px 0;}.CodeMirror pre {padding: 0 4px;}.CodeMirror pre.CodeMirror-line {min-height: 24px;}.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {background-color: white;}.CodeMirror-gutters {border-right: 1px solid #ddd; background-color: #f7f7f7; white-space: nowrap;}.CodeMirror-linenumbers {}.CodeMirror-linenumber {padding: 0 3px 0 5px; min-width: 20px; text-align: right; color: #999; white-space: nowrap;}.CodeMirror-guttermarker {color: black;}.CodeMirror-guttermarker-subtle {color: #999;}.CodeMirror-cursor {border-left: 1px solid black; border-right: none; width: 0;}.CodeMirror div.CodeMirror-secondarycursor {border-left: 1px solid silver;}.cm-fat-cursor .CodeMirror-cursor {width: auto; border: 0 !important; background: #7e7;}.cm-fat-cursor div.CodeMirror-cursors {z-index: 1;}.cm-fat-cursor-mark {background-color: rgba(20, 255, 20, 0.5);-webkit-animation: blink 1.06s steps(1) infinite;-moz-animation: blink 1.06s steps(1) infinite;animation: blink 1.06s steps(1) infinite;}.cm-animate-fat-cursor {width: auto; border: 0; -webkit-animation: blink 1.06s steps(1) infinite; -moz-animation: blink 1.06s steps(1) infinite; animation: blink 1.06s steps(1) infinite; background-color: #7e7;}@-moz-keyframes blink { 0% {} 50% { background-color: transparent; } 100% {}}@-webkit-keyframes blink { 0% {} 50% { background-color: transparent; } 100% {}}@keyframes blink { 0% {} 50% { background-color: transparent; } 100% {}}.CodeMirror-overwrite .CodeMirror-cursor {}.cm-tab { display: inline-block; text-decoration: inherit; }.CodeMirror-rulers {position: absolute; left: 0; right: 0; top: -50px; bottom: -20px; overflow: hidden;}.CodeMirror-ruler {border-left: 1px solid #ccc; top: 0; bottom: 0; position: absolute;}.cm-s-default .cm-header {color: blue;}.cm-s-default .cm-quote {color: #090;}.cm-negative {color: #d44;}.cm-positive {color: #292;}.cm-header, .cm-strong {font-weight: bold;}.cm-em {font-style: italic;}.cm-link {text-decoration: underline;}.cm-strikethrough {text-decoration: line-through;}.cm-s-default .cm-keyword {color: #708;}.cm-s-default .cm-atom {color: #219;}.cm-s-default .cm-number {color: #164;}.cm-s-default .cm-def {color: #00f;}.cm-s-default .cm-variable,.cm-s-default .cm-punctuation,.cm-s-default .cm-property,.cm-s-default .cm-operator {}.cm-s-default .cm-variable-2 {color: #05a;}.cm-s-default .cm-variable-3 {color: #085;}.cm-s-default .cm-comment {color: #a50;}.cm-s-default .cm-string {color: #a11;}.cm-s-default .cm-string-2 {color: #f50;}.cm-s-default .cm-meta {color: #555;}.cm-s-default .cm-qualifier {color: #555;}.cm-s-default .cm-builtin {color: #30a;}.cm-s-default .cm-bracket {color: #997;}.cm-s-default .cm-tag {color: #170;}.cm-s-default .cm-attribute {color: #00c;}.cm-s-default .cm-hr {color: #999;}.cm-s-default .cm-link {color: #00c;}.cm-s-default .cm-error {color: #f00;}.cm-invalidchar {color: #f00;}.CodeMirror-composing { border-bottom: 2px solid; }div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }.CodeMirror-activeline-background {background: #e8f2ff;}.CodeMirror {position: relative; background: #f5f5f5;}.CodeMirror-scroll {overflow: hidden !important; margin-bottom: 0; margin-right: -30px; padding: 16px 30px 16px 0; outline: none; position: relative;}.CodeMirror-sizer {position: relative; border-right: 30px solid transparent;}.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {position: absolute; z-index: 6; display: none;}.CodeMirror-vscrollbar {right: 0; top: 0; overflow-x: hidden; overflow-y: scroll;}.CodeMirror-hscrollbar {bottom: 0; left: 0 !important; overflow-y: hidden; overflow-x: scroll;pointer-events: auto !important;outline: none;}.CodeMirror-scrollbar-filler {right: 0; bottom: 0;}.CodeMirror-gutter-filler {left: 0; bottom: 0;}.CodeMirror-gutters {position: absolute; left: 0; top: 0; min-height: 100%; z-index: 3;}.CodeMirror-gutter {white-space: normal; height: 100%; display: inline-block; vertical-align: top; margin-bottom: -30px;}.CodeMirror-gutter-wrapper {position: absolute; z-index: 4; background: none !important; border: none !important;}.CodeMirror-gutter-background {position: absolute; top: 0; bottom: 0; z-index: 4;}.CodeMirror-gutter-elt {position: absolute; cursor: default; z-index: 4;}.CodeMirror-gutter-wrapper ::selection { background-color: transparent }.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }.CodeMirror-lines {cursor: text; min-height: 1px;}.CodeMirror pre {-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border-width: 0; background: transparent; font-family: inherit; font-size: inherit; margin: 0; white-space: pre; word-wrap: normal; line-height: inherit; color: inherit; z-index: 2; position: relative; overflow: visible; -webkit-tap-highlight-color: transparent; -webkit-font-variant-ligatures: contextual; font-variant-ligatures: contextual;}.CodeMirror-wrap pre {word-wrap: break-word; white-space: pre-wrap; word-break: normal;}.CodeMirror-linebackground {position: absolute; left: 0; right: 0; top: 0; bottom: 0; z-index: 0;}.CodeMirror-linewidget {position: relative; z-index: 2; padding: 0.1px;}.CodeMirror-widget {}.CodeMirror-rtl pre { direction: rtl; }.CodeMirror-code {outline: none;}.CodeMirror-scroll,.CodeMirror-sizer,.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber {-moz-box-sizing: content-box; box-sizing: content-box;}.CodeMirror-measure {position: absolute; width: 100%; height: 0; overflow: hidden; visibility: hidden;}.CodeMirror-cursor {position: absolute; pointer-events: none;}.CodeMirror-measure pre { position: static; }div.CodeMirror-cursors {visibility: hidden; position: relative; z-index: 3;}div.CodeMirror-dragcursors {visibility: visible;}.CodeMirror-focused div.CodeMirror-cursors {visibility: visible;}.CodeMirror-selected { background: #d9d9d9; }.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }.CodeMirror-crosshair { cursor: crosshair; }.CodeMirror-line::selection, .CodeMirror-line >--> span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }.cm-searching {background: #ffa; background: rgba(255, 255, 0, .4);}.cm-force-border { padding-right: .1px; }@media print { .CodeMirror div.CodeMirror-cursors {visibility: hidden;}}.cm-tab-wrap-hack:after { content: ""; }span.CodeMirror-selectedtext { background: none; }.CodeMirror-activeline-background, .CodeMirror-selected {transition: visibility 0ms 100ms;}.CodeMirror-blur .CodeMirror-activeline-background, .CodeMirror-blur .CodeMirror-selected {visibility:hidden;}.CodeMirror-blur .CodeMirror-matchingbracket {color:inherit !important;outline:none !important;text-decoration:none !important;}.CodeMirror-sizer {min-height:auto !important;}
-->
<!--
.cm-s-material.CodeMirror {background-color: #263238; color: rgba(233, 237, 237, 1);}.cm-s-material .CodeMirror-gutters {background: #263238; color: rgb(83,127,126); border: none;}.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line >--> span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }.cm-s-material .cm-variable-2 { color: #80CBC4; }.cm-s-material .cm-variable-3 { color: #82B1FF; }.cm-s-material .cm-builtin { color: #DECB6B; }.cm-s-material .cm-atom { color: #F77669; }.cm-s-material .cm-number { color: #F77669; }.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }.cm-s-material .cm-string { color: #C3E88D; }.cm-s-material .cm-string-2 { color: #80CBC4; }.cm-s-material .cm-comment { color: #546E7A; }.cm-s-material .cm-variable { color: #82B1FF; }.cm-s-material .cm-tag { color: #80CBC4; }.cm-s-material .cm-meta { color: #80CBC4; }.cm-s-material .cm-attribute { color: #FFCB6B; }.cm-s-material .cm-property { color: #80CBAE; }.cm-s-material .cm-qualifier { color: #DECB6B; }.cm-s-material .cm-variable-3 { color: #DECB6B; }.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }.cm-s-material .cm-error {color: rgba(255, 255, 255, 1.0); background-color: #EC5F67;}.cm-s-material .CodeMirror-matchingbracket {text-decoration: underline; color: white !important;}
-->
<!--
.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; }.cm-s-monokai div.CodeMirror-selected { background: #49483E; }.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line >--> span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); }.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); }.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; }.cm-s-monokai .CodeMirror-guttermarker { color: white; }.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; }.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; }.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }.cm-s-monokai span.cm-comment { color: #75715e; }.cm-s-monokai span.cm-atom { color: #ae81ff; }.cm-s-monokai span.cm-number { color: #ae81ff; }.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; }.cm-s-monokai span.cm-keyword { color: #f92672; }.cm-s-monokai span.cm-builtin { color: #66d9ef; }.cm-s-monokai span.cm-string { color: #e6db74; }.cm-s-monokai span.cm-variable { color: #f8f8f2; }.cm-s-monokai span.cm-variable-2 { color: #9effff; }.cm-s-monokai span.cm-variable-3 { color: #66d9ef; }.cm-s-monokai span.cm-def { color: #fd971f; }.cm-s-monokai span.cm-bracket { color: #f8f8f2; }.cm-s-monokai span.cm-tag { color: #f92672; }.cm-s-monokai span.cm-header { color: #ae81ff; }.cm-s-monokai span.cm-link { color: #ae81ff; }.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; }.cm-s-monokai .CodeMirror-activeline-background { background: #373831; }.cm-s-monokai .CodeMirror-matchingbracket {text-decoration: underline; color: white !important;}
-->
<!--
html, .wiz-editor-body {font-size: 12pt;}.wiz-editor-body {font-family: Helvetica, 'Hiragino Sans GB', '微软雅黑', 'Microsoft YaHei UI', SimSun, SimHei, arial, sans-serif;line-height: 1.7;margin: 0 auto;padding: 20px 16px;padding: 1.25rem 1rem;}.wiz-editor-body h1,.wiz-editor-body h2,.wiz-editor-body h3,.wiz-editor-body h4,.wiz-editor-body h5,.wiz-editor-body h6 {margin:20px 0 10px;margin:1.25rem 0 0.625rem;padding: 0;font-weight: bold;}.wiz-editor-body h1 {font-size:20pt;font-size:1.67rem;}.wiz-editor-body h2 {font-size:18pt;font-size:1.5rem;}.wiz-editor-body h3 {font-size:15pt;font-size:1.25rem;}.wiz-editor-body h4 {font-size:14pt;font-size:1.17rem;}.wiz-editor-body h5 {font-size:12pt;font-size:1rem;}.wiz-editor-body h6 {font-size:12pt;font-size:1rem;color: #777777;margin: 1rem 0;}.wiz-editor-body div,.wiz-editor-body p,.wiz-editor-body ul,.wiz-editor-body ol,.wiz-editor-body dl,.wiz-editor-body li {margin:8px 0;}.wiz-editor-body blockquote,.wiz-editor-body table,.wiz-editor-body pre,.wiz-editor-body code {margin:8px 0;}.wiz-editor-body .CodeMirror pre {margin:0;}.wiz-editor-body a {word-wrap: break-word;text-decoration-skip-ink: none;}.wiz-editor-body ul,.wiz-editor-body ol {padding-left:32px;padding-left:2rem;}.wiz-editor-body ol.wiz-list-level1 >--> li {list-style-type:decimal;}.wiz-editor-body ol.wiz-list-level2 > li {list-style-type:lower-latin;}.wiz-editor-body ol.wiz-list-level3 > li {list-style-type:lower-roman;}.wiz-editor-body li.wiz-list-align-style {list-style-position: inside; margin-left: -1em;}.wiz-editor-body blockquote {padding: 0 12px;}.wiz-editor-body blockquote > :first-child {margin-top:0;}.wiz-editor-body blockquote > :last-child {margin-bottom:0;}.wiz-editor-body img {border:0;max-width:100%;height:auto !important;margin:2px 0;}.wiz-editor-body table {border-collapse:collapse;border:1px solid #bbbbbb;}.wiz-editor-body td,.wiz-editor-body th {padding:4px 8px;border-collapse:collapse;border:1px solid #bbbbbb;min-height:28px;word-break:break-word;box-sizing: border-box;}.wiz-editor-body td > div:first-child {margin-top:0;}.wiz-editor-body td > div:last-child {margin-bottom:0;}.wiz-editor-body img.wiz-svg-image {box-shadow:1px 1px 4px #E8E8E8;}.wiz-hide {display:none !important;}
-->

Locust 性能测试工具安装使用说明的相关教程结束。

《Locust 性能测试工具安装使用说明.doc》

下载本文的Word格式文档,以方便收藏与打印。