脚本分析
单接口脚本
一个测试类对象中添加多个测试任务(方法),通过@task 标识该方法是否为测试类,@task(N) 配置测试任务在整个测试对象Live中的权重。
提供on_start(self),on_stop(self) 方法设置自定义任务开始和结束,每个用户仅执行一次。
写在前面:
脚本中的url 坚决的不要带上环境地址,只允许写path 路径,举例:
错误:https:/baidu.com/apollo/public/getLargeClass?p=w&
正确:/apollo/public/businessLive/getLargeClasst?p=w&
坑点原因说明:在执行测试时,task任务中指定的host 无法覆盖 请求url 中的host !!!!!
多任务脚本(单接口测试):
from locust import HttpUser, task, TaskSet
from api.gettoken import login_b_withToken
class Live(TaskSet):#
def on_start(self): #每个User初始化一次
print("~~~~~start~~~~~")
self.token = "c2a2d7a6aea3456a8ae5ea42034eeb21"
@task(2) #设置该方法是否为执行任务,(2)标识 该任务在该类任务中的权重 1:2:3 ,可以理解为种子数相对比例
def getInteractionClassLiveList(self):
# client 方法
self.client.post(
f"/public/getInteraction?p=w&v=v5.4.8&userType=B&token={self.token}",
json={
"current": 1,
"size": 10,
"courseName": "sss"
})
@task(3)
def getLargeClassLiveList(self):
self.client.post(
f"/public/getInteraction2?p=w&v=v5.4.8&userType=B&token={self.token}",
json={
"current": 1,
"size": 10,
})
def on_stop(self): # 默认会执行
print("~~~~~stop~~~~~")
class User(HttpUser):
tasks = [Live] # tasks指定的任务类对象设置,把该类任务放入统一list中
host = "https://baidu.com" #被测主机地址
min_wait = 1000
max_wait = 5000
单任务多接口脚本(串行链路):
适合1v1链路测试
class show_test(TaskSet):
@task
def createShow(self):
data = {"title": "英语启蒙陪伴营",
"deadline": 1615734000256,
"startTime": 1614506365256,
"activityType": "312",
"templateId": "312"}
show = self.client.post("/sho", json=data)
print(show.json())
activityId = show.json()['result']
# 发布
json = {"activityId": activityId}
res = self.client.post(
"/public/business?p=w&",
json=json)
print(res.text)
class User(HttpUser):
tasks = [show_test] # tasks指定的任务类对象设置,把该类任务放入统一list中
host = "https://baidu.com" #被测主机地址
min_wait = 1000
max_wait = 5000
特别得HttpUser类
它在HttpUser 类中,源码说明:This class creates a *client* attribute on instantiation which is an HTTP client with support for keeping a user session between requests.
翻译:这个类在实例化时创建一个*client*属性,它是一个HTTP客户机,支持在请求之间保持用户会话。
client 是一个HttpSession 类型
client: HttpSession = None
"""
Instance of HttpSession that is created upon instantiation of Locust.
The client supports cookies, and therefore keeps the session between HTTP requests.
"""
翻译:在实例化时创建的HttpSession的实例蝗虫客户端支持cookies,因此在HTTP请求之间保持会话。
理解:在任务执行开始之前,首先会实例化一个HttpUser 对象,这个对象中有一个属性交client ,这个属性是一个HttpSession 的类型。
再来看看HttpSession,class HttpSession(requests.Session):
它继承了requests 的Session 类,并且重写了父类的requets 方法,重写方法中去处理了一些相应结果数据和请求数据,源码如下:
response = self._send_request_safe_mode(method, url, **kwargs)
# record the consumed time
request_meta["response_time"] = (time.monotonic() - request_meta["start_time"]) * 1000
request_meta["name"] = name or (response.history and response.history[0] or response).request.path_url
# get the length of the content, but if the argument stream is set to True, we take
# the size from the content-length header, in order to not trigger fetching of the body
if kwargs.get("stream", False):
request_meta["content_size"] = int(response.headers.get("content-length") or 0)
else:
request_meta["content_size"] = len(response.content or b"")
if catch_response:
response.locust_request_meta = request_meta
return ResponseContextManager(
response, request_success=self.request_success, request_failure=self.request_failure
)
else:
if name:
# Since we use the Exception message when grouping failures, in order to not get
# multiple failure entries for different URLs for the same name argument, we need
# to temporarily override the response.url attribute
orig_url = response.url
response.url = name
try:
response.raise_for_status()
except RequestException as e:
self.request_failure.fire(
request_type=request_meta["method"],
name=request_meta["name"],
response_time=request_meta["response_time"],
response_length=request_meta["content_size"],
exception=e,
)
else:
self.request_success.fire(
request_type=request_meta["method"],
name=request_meta["name"],
response_time=request_meta["response_time"],
response_length=request_meta["content_size"],
)
if name:
response.url = orig_url
return response
而请求方式是完全沿用父类方法,源码如下:
def _send_request_safe_mode(self, method, url, **kwargs):
"""
Send an HTTP request, and catch any exception that might occur due to connection problems.
Safe mode has been removed from requests 1.x.
"""
try:
#调用父类request.Session 的请求方法
return super().request(method, url, **kwargs)
except (MissingSchema, InvalidSchema, InvalidURL):
raise
except RequestException as e:
r = LocustResponse()
r.error = e
r.status_code = 0 # with this status_code, content returns None
r.request = Request(method, url).prepare()
return r
因此这里的请求方式完全符合requests库 的所有规范,不存在更多的学习成本。
测试集合
创建一个task_runner.py 文件
class User(HttpUser):
tasks = [Server, Live] # 把所有可执行类收录进来,统一执行
host = "https://baidu.com"
cmd 中进入工程目录:
locust -f tasks_runner.py
然后打开web页面,设置用户上限和增长数 ,开始执行压测