关于性能压测工具Locust的使用

  关于断言 

       与jmeter中设置断言相似,某些情况下需要对请求返回值状态做一个判断,比如在请求一个接口时,可以通过断言来判断返回的http状态码是否为200;通常在locust中通过with self.client.get/post/put("url地址",catch_response=True) as response的形式实现断言;response.status_code获取http响应码进行判断,失败后会加到统计错误表中。

       需设置catch_response=True,否则断言无效,默认catch_response=False。

       下面例子中,使用断言对获取账号token的接口,首先使用python断言(assert)对接口返回值进行判断(python断言不通过,代码就不向下执行,acquire_regiscodes任务函数post请求数为0),通过response.status_code 得请求响应的http状态码,并判断其是否为200,否则response.failure([Failed])。

#!/usr/local/python3/bin/python3
import json
from locust import TaskSet,Locust,task,between,HttpLocust

headers = {'Content-Type':'application/json;charset=UTF-8'}
class ScriptTasks(TaskSet):
#   def __init__(self):
#       super(eval(self.__class__.__name__),self).__init__()
#       self._headers = {'Content-Type':'application/json;charset=UTF-8'}
    def on_start(self):
        body = {
            "key": '***********',
            "secret": '*********'
                }
        response = self.client.post("/api/v1/token",json=body,headers=headers,verify=False)
        response_json = json.loads(response.text)
        self._accessToken = response_json['data']['Token']
    @task
    def acquire_regiscodes(self):
        uri = '/api/v1/getlift?token={0}'.format(self._accessToken)
        #self.client属性使用Python request库的所有方法,调用和使用方法和requests完全一致
        with   self.client.post(url=uri,headers=headers,catch_response=True) as response:
            assert json.loads(response.text)['message'] == 'ok' #python断言对接口返回值中的message字段进行断言
            if response.status_code == 200: #对http响应码是否200进行判断
                response.success()
            else:
                response.failure("GetRegistryCodes[Failed!]")

#WebsiteUser()类: 用于定义模拟用户
class WebsiteUser(HttpLocust):
    #指向一个定义了的用户行为类
    task_set = ScriptTasks
    #指定被测试应用的URL的地址
    host = "http://test.haha.com"
    wait_time = between(1,2)

启动测试,并观察运行情况:

 

关于顺序执行的TaskSet

如果需要执行的任务是按照一定顺序执行的,那么就可以继承TaskSequence类来实现。

例如:先拿到全部的电梯编码--->再随机访问某一电梯编码对应电梯基本信息--->获取该台电梯全部详细信息

#!/usr/local/python3/bin/python3.6
import json
import os
from locust import TaskSet,Locust,task,between,HttpLocust,TaskSequence,seq_task
headers = {'Content-Type':'application/json;charset=UTF-8'}
class ScriptTasks(TaskSequence):

    #获取用户token,存入txt文本
    def setup(self):
        body = {
            "AppKey": '*************',
            "AppSecret": '****************'
                }
        response = self.client.post("/api/v1/token",json=body,headers=headers)
        response_json = json.loads(response.text)
        token = response_json['data']['accessToken']
        with open('token.txt','w') as file:
            file.write(token)
    
    #获取电梯注册编码
    def on_start(self):
        lift_codes = []
        with open('token.txt','r') as  file:
            self._token = file.read()
        uri = '/api/v1/getlift?token={0}'.format(self._token)
        with self.client.post(url=uri, headers=headers,catch_response=True) as  response:
            response_code = json.loads(response.text)['data']
            try:
                for lift in response_code:
                    if not lift.get('registerCode') is None:
                        lift_codes.append(lift.get('registerCode'))
            finally:
                self._lift_codes = lift_codes

    #获取单台电梯基本信息
    @seq_task(1)
    @task(5)
    def acquire_lift_information(self):
        import random
        self._regis_code  = str(random.sample(self._lift_codes,1)[0])
        body = {
            #随机抽取一个在setup方法中获取的电梯编号发起接口请求
            "registerCodes": [self._regis_code]
        }
        uri = '/api/v1/liftinformation?token={0}'.format(self._token)
        #self.client属性使用Python request库的所有方法,调用和使用方法和requests完全一致
        self.client.post(url=uri,headers=headers,json=body)

    #获取单台电梯详细信息
    @seq_task(2)
    @task(10)
    def earn_lift_detials(self):
        uri = '/api/v1/liftdetail?token={0}'.format(self._token)
        body = {
            "registerCode": "{0}".format(self._regis_code)
                }
        self.client.post(url=uri,headers=headers,json=body)



#WebsiteUser()类: 用于定义模拟用户
class User(HttpLocust):
    task_set = ScriptTasks
    host = "http://test.haha.com"
    #between方法用于模拟用户在每次执行任务后等待介于最小值和最大值之间的随机时间,单位秒
    wait_time = between(1,2) 

1.使用@seq_task指定来顺序执行,如果没有该注解,默认顺序是1;如果排序相同,会根据函数方法名称的字母顺序排序

2.每当一轮任务被按照顺序执行完成后,会重头开始执行新一轮的任务

3.由于不再是随机选择任务执行,框架会直接使用@task指定权重作为执行次数,如果没有该注解,默认执行1次

PS:

       不同与每次虚拟用户开始任务集时都会执行的on_start,setup函数仅执行一次,Locust类和TaskSet类都可以定义setup函数,执行顺序如下

 Locust setup          第一次启动Locust的时候执行
TaskSet setup          第一次实例化任务集时执行
TaskSet on_start      每一次开始一个任务时执行

      这里,由于我们压测的主要接口不是获取账号token以及获取完整的电梯注册列表,所以通过setup方法在压测任务开始前只获取一次token提供给所有虚拟线程用户;利用on_start方法在一个模拟用户发起一次完整任务请求时去提取电梯注册码并生成一个列表对象,以避免该接口执行的过长耗时对整改压测结果产生影响。

 

关于Locust的分布式

       同Jmeter一样,Locust也能够支持运行在多台机器中进行分布式压力测试,来避免应单台客户端因硬件、网络等资源瓶颈等带来的任务线程数(即模拟所需的用户数量)达不到预期设定值的问题。

      相关设置

      master端

locust -f locustfile.py --master --master-bind-host=192.168.1.12 --master-bind-port=5557 --run-time 1m --no-web 

--master  以主服务模式启动Locust,web界面打开也是以此机IP为地址

 --master-bind-host 用于主服务指定一个ip地址,可选项

 --master-bind-port 用于主服务设置一个固定的端口,主节点的端口默认是5557,可选项

    slave端

 locust -f locustfile.py --slave --master-host=192.168.1.12 --master-port=5557

--slave 以从属服务模式启动Locust

--master-host  用于从属服务指定主服务的地址,可选项

--master-port 用于从属服务指定主服务的端口,可选项

--expect-slaves

如果在没有Web UI的情况下运行Locust,在启动主节点时加上--expect-slaves指定选项,以指定预期连接的从节点数。然后,在开始测试之前,将等待这些从属节点连接

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值