[python] request 介面測試自動化指令碼轉化為 [locust] 效能測試指令碼
request介面測試自動化指令碼轉化為locust效能測試指令碼
一、目標說明
1、locust 可以呼叫request的封裝介面(比如登入)
2、對locust請求數進行部分控制優化
3、可以作為快速造資料的一種手段
4、locust適配版本為 v1.1(0版本需要自己修改一下相關程式碼引數與部分邏輯)
二、實現原理
1、對request進行二次封裝,同時實現locust程式碼記錄轉換
2、依據locust底層採用了request的session,因此替換session即可(RequestsBasic)
三、核心程式碼邏輯
3.1 requests_basic.py request二次封裝,核心轉化模組
import time
import urllib3
import requests
import threading
import sys
from collections import namedtuple
import traceback
from utils import logger
from utils.logger import log #此處的log 可以直接用系統的 logging
class RequestsBasic(object):
urllib3.disable_warnings() # 去掉驗證證照告警問題
#相關類變數:
locust_start_time=None #統計 locust 開始傳送請求的時間
#預設headers,可以設定更改
default_headers = {
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept": "application/json, text/plain, */*",
"Connection": "keep-alive",
"User-Agent":
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"}
def __init__(self,http_client_session=None):
self.http_client_session = http_client_session or requests.Session()
self.verify = False #預設設定是否需要進證照校驗,預設不需要(主要https用)
self.requests = requests #預設模組為一個物件,留作擴充套件
self.headers = self.get_default_headers()
self.proxies = {'http': 'http://127.0.0.1:8888',
'https': 'https://127.0.0.1:8888'}#這個與使用抓包工具的代理有關如:我的fildder 用的是8888 埠
self.proxies_open=0 #預設關閉不使用代理
self.locust_client_dict:dict={} #根據執行緒id存放不同的客戶端user.client
self.locust_count =0 #統計該程式執行時 傳送 locust http請求個數
self.runtimes=1 # 執行次數,非locust請求時 增加失敗重發機制
# locust_response_json_assert 針對locust的響應進行處理其是否成功或者失敗,可另外進行擴充套件,比如加入大於小於等於等進行判斷
self.locust_response_json_assert={}
self.locust_name_flag = 1 # 對locust 請求時 設定 name引數設定,否則不設定url的名字
def get_locust_client_dict(self,locust_client):
"""
替換 request中 的session 為單獨使用者的 locust_client,在locust 中的 on_start 方法中呼叫
:param locust_client: 在locust 中一般為 self.client
eg:my_request.get_locust_client_dict(self.client)
:return: 返回 self 該類的例項化本身,因為此處在每個執行緒,每個user.client是有細微差異方便對該類例項化物件進行設定
"""
"""
:return:
"""
thread_id = threading.current_thread().ident # 記錄當前執行緒id
self.locust_client_dict[thread_id] = locust_client # 注意設定此項,且保證 my_request 是同一個不可變的物件
return self #注意此處,返回的不同 RequestsBasic 物件
#預設設定請求的 Content-Type
def get_default_headers(self,content_type=1,default_headers=None):
"""
獲取預設的請求頭
:param content_type:
:param default_headers:
:return:
"""
headers ={
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept": "application/json, text/plain, */*",
"Connection": "keep-alive",
"User-Agent":
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36"}
if default_headers !=None:
headers=default_headers
if content_type ==-1:
pass #無 Content-Type 屬性
elif content_type ==0:
headers['Content-Type']="application/json; charset=UTF-8"
elif content_type==1:
headers['Content-Type'] = "application/x-www-form-urlencoded; charset=UTF-8"
elif content_type ==2:
headers['Content-Type'] = "multipart/form-data"
return headers
def request(self, method, url, locust_client=None, locust_response_json_assert_dict:dict=None,**kwargs):
"""
支援request請求,和locust請求(以locust* 開頭的引數都是locust特有)
:param method: #methods= ('post','put','get','delete') #可以參考 request的request方法
:param locust_client: locust的客戶端,或者設定 self.locust_client_dict 物件
:param locust_response_json_assert_dict: locust時對返回的response 引數進行特殊斷言
:param url:
:param
:param kwargs:
:return:
"""
#、設定返回相關引數,設定一個namedtuple物件,進行一些引數封裝
request_meta = namedtuple('RequestsMeta',
['start_time', 'elapsed_time', 'response', 'content_size', 'status_code'])
request_meta.start_time = time.time() #統計時間
param_info = {"method": method, "url": url, "kwargs": kwargs} # 異常處理時呼叫引數
#print("locust_response_json_assert_dict:", locust_response_json_assert_dict,kwargs)
# 開始發起http/https請求
try:
#1、處理請求頭
if 'verify' not in kwargs.keys():
kwargs['verify'] = self.verify
if 'headers' not in kwargs.keys():
kwargs['headers'] = self.headers
# urllib3.disable_warnings() # 去掉驗證證照告警問題
#2、處理locust和普通請求
if locust_client == None and len(self.locust_client_dict)== 0: #普通請求
#處理代理
if self.proxies_open == 1:
# "proxies" in kwargs.keys() and kwargs['proxies'] != None
kwargs['proxies']=self.proxies
log.warning("此處使用了代理協議請檢查(若未開代理可能會失敗!)"
"proxies:{}".format(kwargs['proxies']))
#支援多次傳送
if 'name' in kwargs.keys():
log.error("【注意】name 引數一般不在 kwargs引數中,locust時特用!目前已廢棄,請注意檢查!")
try:
runtimes = 1 #普通請求,多次嘗試計數
while runtimes <= self.runtimes:
response = self.http_client_session.request(method, url, **kwargs)
# log.info(runtimes,self.runtimes,response.status_code)
# print("runtimes:", runtimes,response.status_code)
if response.status_code != 200 and self.runtimes > 1:
elapsed_time = int((time.time() - request_meta.start_time) * 1000) # 毫秒
log.warning("""runtimes:{}
,耗時:{} ms,返回狀態碼:{}""(!=200),請檢查請求:\n{}\n【返回值】:{}
""".format(runtimes, elapsed_time,response.status_code, param_info, response.text))
time.sleep(runtimes * 2)
request_meta.start_time = time.time() # 重新記錄開始時間
else:
break
runtimes += 1 # 自增執行的次數
except Exception as e:
log.warning("runtimes:{} 執行失敗,請檢查:{}".format(runtimes,traceback.format_exc()))
#其他處理
#log.debug("session:{}".format(response.cookies))
# 異常處理
if response.status_code != 200:
log.warning("""返回狀態碼:{}(!=200),
請檢查請求:\n{}\n【返回值】:{}
""".format(response.status_code, param_info,response.text))
else: # 走locust
self.locust_count +=1 #統計locust傳送的請求次數
if self.locust_count <=1:
self.locust_start_time= time.time() #統計從locust傳送的第一個請求開始計時
thread_id = threading.current_thread().ident # 獲取當前執行緒id
#拿取 locust_client
if locust_client != None:
#使用自己本身
self.locust_client_dict[thread_id]=locust_client # 獲取當前執行緒的 user.client
else:
locust_client = self.locust_client_dict[thread_id]
if self.locust_name_flag ==1 and "?" in url:
if 'name' not in kwargs:
url_pre = url.split("?")[0]
kwargs['name'] = url_pre
log.warning("對locust的 name(url) 引數進行特殊為:{}".format(url))
# 傳送請求: 注意 catch_response
elapsed_time_total = int((time.time() - self.locust_start_time) * 1000)
locust_count=self.locust_count #locust 當前統計的次數
print('{}次請求中!總耗時(ms):'.format(locust_count),elapsed_time_total,"執行緒id:{}".format(thread_id),url, "除錯列印locust_response_json_assert_dict:",
locust_response_json_assert_dict)
with locust_client.request(method, url,catch_response=True, **kwargs) as response:
if hasattr(response, 'elapsed'):
elapsed=response.elapsed
elapsed_time_total = int((time.time() - self.locust_start_time) * 1000)
print("{}次請求完!總耗時(ms):".format(locust_count),elapsed_time_total,'本次耗時:',elapsed,"執行緒id:{}".format(thread_id),url,)
else:
elapsed=''
if response.status_code < 400:
response.success()
# 處理json統計介面是否失敗
#進行 locust_response_json_assert_dict 特殊處理
if "locust_response_json_assert_dict" in kwargs.keys():
locust_response_json_assert_dict = kwargs['locust_response_json_assert_dict']
# print("request:locust_response_json_assert_dict:",locust_response_json_assert_dict,kwargs)
if locust_response_json_assert_dict != None:
try:
data_dict = response.json()
for k, v in locust_response_json_assert_dict.items():
if k in data_dict and data_dict[k] == locust_response_json_assert_dict[k]:
response.success()
else:
response.failure('json檢查k,v:{} 失敗!{}'.format((k, v), response.text))
except Exception as e:
print("處理locust_response_json_assert_dict異常:\n", traceback.format_exc())
finally:
pass
else:
#注意此處
response.failure('elapsed:{} 狀態碼:{} 失敗!{}'.format(0,response.status_code,response.text))
# response.r
response.encoding = 'utf-8'
# response.content.decode("unicode_escape")
request_meta.elapsed_time = int((time.time() - request_meta.start_time) * 1000) # 毫秒
request_meta.status_code = response.status_code
request_meta.response = response
request_meta.content_size = int(response.headers.get("content-length") or 0)
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(),**kwargs)
raise e
# log.error("【錯誤詳細資訊】:\n" + traceback.format_exc())
return request_meta
def request_except_deal(self,e,traceback,result='',**kwargs):
"""
#處理介面異常資訊
:param e: 捕獲到的異常類
:param traceback: 異常相關資訊
:return: 異常型別
"""
try:
except_type = type(e)
if type(result)!=str:
text = result.response.text
else:
text=""
log.warning("text:{}\n丟擲異常型別為:{},異常資訊為:{}\n引數為:{}".format(text,except_type,traceback,kwargs))
except Exception as e:
print("處理request報錯異常(print):",traceback.format_exc())
return except_type
#例項化一個預設物件
my_request=RequestsBasic()
if __name__ == "__main__":
print("開始測試",my_request.headers)
四、使用示例
4.1 ut_basic.py 對http請求的一個封裝,可以跑介面測試,也可以跑locust 效能測試
#!/usr/bin/env python
# coding:utf-8
"""
@author:YuanPengCheng
@PROJECT_NAME:autoTest
@file:UT_basic.py
@createtime:2020/8/6 9:22
@software: PyCharm
@description:
"系統效能框架測試模組 unittest(UT)"
"""
import traceback
import random
# sys.path.append(os.getcwd())
from common.http import requests_basic #核心程式碼 requests_basic.py
from utils.logger import log
from utils.testTools import tools #一些常用小工具封裝,可以自己去替換
my_request = requests_basic.RequestsBasic() # 初始化一個 http請求,防止不同的物件的請求混亂
my_request.headers = my_request.get_default_headers(content_type=0) # 設定請求頭的型別
# proxies_my = my_request.proxies # debug時 是否開啟代理抓包模式
proxies_my=None
class UTBasic():
def __init__(self):
self.my_request = my_request
self.url_basic='' #:9900
self.ut_path= "/UT" # self.ut_path='' ,預設走閘道器
pass
#獲取伺服器時間(即空介面測試)
def getGlobalTime(self,**kwargs):
"""
獲取伺服器時間(即空介面測試)
:param kwargs:
:return:
"""
try:
# /dp_server/api/connect/list
url = self.url_basic + "{}/mock/testRecordData/getGlobalTime".format(self.ut_path)
# searchContent
payload = {}
for k, v in kwargs.items(): # 對函式關鍵字進行處理,
payload[k] = v
result = my_request.request('get', url=url, data=payload,**kwargs)
log.info(url,result.elapsed_time,'ms ' ,result.response.text)
# data_dict = result.response.json()
# return data_dict
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#Mysql資料批量儲存介面
def mysql_saveList(self,dataSize=20,**kwargs):
"""
Mysql資料批量儲存介面
:param kwargs:
:return:
"""
try:
# /dp_server/api/connect/list
url = self.url_basic + "{}/mock/testRecordData/saveList?dataSize={}".format(self.ut_path,dataSize)
# searchContent
payload ={}
for k, v in kwargs.items(): # 對函式關鍵字進行處理,
payload[k] = v
result = my_request.request('get', url=url, params=payload,**kwargs)
print(result.elapsed_time,'ms ' ,url,result.response.elapsed,url,result.response.text)
# data_dict = result.response.json()
# return data_dict
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#跨服務呼叫空介面,深度和層次
def crossServiceLoopByDeep(self,callCount=1,deep=5,**kwargs):
"""
Mysql資料批量儲存介面
callCount:呼叫鏈路號(Int),用於區分呼叫的次數,每次呼叫可遞增
deep:跨服務呼叫深度(Int)
:param kwargs:
:return:
"""
try:
print("(callCount,deep):",(callCount,deep))
# /dp_server/api/connect/list
url = self.url_basic + "{}/mock/testRecordData/crossServiceLoopByDeep?callCount={}&deep={}".format(self.ut_path,callCount,deep)
# searchContent
payload = {}
for k, v in kwargs.items(): # 對函式關鍵字進行處理,
payload[k] = v
result = my_request.request('get', url=url, params=payload,**kwargs)
print(result.elapsed_time,'ms ' ,(callCount,deep),url,result.response.text)
# data_dict = result.response.json()
# return data_dict
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#mysql 高階查詢
def search(self,filter: str, pageIndex=0,pageSize=10,sortField='', sortOrder='', **kwargs):
"""
:param filter: 是一個 字串的 list[dict]
[{"operation":"like","alias":"","dataType":"","fieldname":"majorName","name":"majorName","value":"06191455%"}]
:param kwargs:
:return:
"""
try:
# /dp_server/api/connect/list
url = self.url_basic + "{}/mock/testRecordData/search".format(self.ut_path)
# searchContent
payload = {'filter': filter,
# [{"operation":"like","alias":"","dataType":"","fieldname":"indexInGroup","name":"indexInGroup","value":"19%"}]
'pageIndex': pageIndex,
'pageSize': pageSize,
'sortField': sortField,
'sortOrder': sortOrder}
result = my_request.request('post', url=url, data=payload,headers=my_request.get_default_headers(1),proxies=proxies_my,**kwargs)
print(result.elapsed_time,'ms ' ,url,"狀態碼:",result.status_code,result.response.elapsed,url,"response.text 資料:\n",result.response.text,"data引數為:\n{}".format(payload))
# print(result.response.text)
data_dict = result.response.json()
# print("1data_dict:",data_dict)
print("search data_dict:\n", "total:", data_dict['total'], "pageSize:", data_dict['pageSize'],
"totalPages:", data_dict['totalPages'])
return data_dict
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#圖資料庫儲存
def saveGraphData(self,dataGroupId:str,linkedSize:int,linkedNum:int, **kwargs):
"""
:param filter: 是一個 字串的 list[dict]
:param kwargs:
:return:
"""
try:
# /dp_server/api/connect/list
#url = self.url_basic + "{}/mock/testGraphData/saveGraphData?dataGroupId={}&linkedSize={}&linkedNum={}".format(self.ut_path,dataGroupId,linkedSize,linkedNum)
url_basic = self.url_basic + "{}/mock/testGraphData/saveGraphData".format(self.ut_path)
url=url_basic+"?dataGroupId={}&linkedSize={}&linkedNum={}".format(dataGroupId,linkedSize,linkedNum)
#?dataGroupId=0001&linkedSize=20&linkedNum=30
payload = {"dataGroupId":dataGroupId,
"linkedSize":linkedSize,
"linkedNum":linkedNum,
}
result = my_request.request('get', url=url, data={},headers=my_request.get_default_headers(1),**kwargs)
print(result.elapsed_time,'ms ' ,url,"\nsaveGraphData text:",[result.response.text])
return result
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#圖資料庫查詢
def findListByNeo4j(self,startLable:str,maxLevel:int,targetLable:str, **kwargs):
"""
:param startLable: ‘Tag’_dataGroupId_編號 是一個組合引數
:param maxLevel: #與儲存時的 linkedSize tag生成的列數有關,幾乎相等,可以小於它,但注意資料關聯
:param targetLable: ‘Tag’_dataGroupId_編號 是一個組合引數,注意與 startLable maxLevel 進行資料關聯
:param kwargs:
:return:
"""
try:
# /dp_server/api/connect/list
#url = self.url_basic + f"{self.ut_path}/mock/testGraphData/findListByNeo4j?startLable={startLable}&maxLevel={maxLevel}&targetLable={targetLable}"
url_basic = self.url_basic + f"{self.ut_path}/mock/testGraphData/findListByNeo4j"
url=url_basic+f"?startLable={startLable}&maxLevel={maxLevel}&targetLable={targetLable}"
#/mock/testGraphData/findListByNeo4j?startLable=Tag_0001_0&maxLevel=20&targetLable=Tag_0001_19
# searchContent
payload = {"startLable":startLable,
"maxLevel":maxLevel,
"targetLable":targetLable}
result = my_request.request('get', url=url, data={},headers=my_request.get_default_headers(1))
print(result.elapsed_time,'ms ' ,url,"\n",[result.response.text])
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#分散式事務驗證介面
def testDistriTransaction(self,dataGroupId:str='555555555', **kwargs):
"""
:param dataGroupId 資料集ID。驗證如果表中不存在該dataGroupId對應的資料即生效
:param kwargs:
:return:
"""
try:
# /dp_server/api/connect/list
url_basic = self.url_basic + f"{self.ut_path}/mock/testRecordData/testDistriTransaction"
url = url_basic + f"?dataGroupId={dataGroupId}"
#:9900/UT/mock/testRecordData/testDistriTransaction?dataGroupId=555555555
payload = {}
result = my_request.request('get', url=url, data=payload,headers=my_request.get_default_headers(1))
print(result.elapsed_time,'ms ' ,url,"\n",[result.response.text])
except Exception as e:
my_request.request_except_deal(e, traceback.format_exc(), result)
raise e
#
#預設生成一個公共物件
utb=UTBasic()
if __name__ == "__main__":
log.set_logpath("/UT/basic/")
utb.my_request.proxies_open=1 #除錯走協議
utb.url_basic='http://10.2.1.150:9900'
#utb.url_basic = 'http://10.2.1.95:9900'
# utb.getGlobalTime()
# utb.crossServiceLoopByDeep()
#搜尋
def test_search():
search_value = '196'
print("開始搜尋:{}".format(search_value))
filter = [
{"operation": "like", "alias": "", "dataType": "", "fieldname": "indexInGroup", "name": "indexInGroup",
"value": "{}%".format(search_value)}]
filter = str(filter).replace("'", '"')
data_dict = utb.search(filter=filter)
print(data_dict)
def testDistriTransaction():
print("開始分散式事務呼叫")
dataGroupId='555555555'
utb.testDistriTransaction(dataGroupId=dataGroupId)
locust_response_json_assert_dict = {"success": True}
filter = [
{"operation": "like", "alias": "", "dataType": "", "fieldname": "dataGroupId", "name": "dataGroupId",
"value": "{}%".format(dataGroupId)}]
filter = str(filter).replace("'", '"')
data_dict = utb.search(filter=filter,locust_response_json_assert_dict=locust_response_json_assert_dict)
print('data_dict:',data_dict)
def test_saveGraphData():
print("開始儲存圖資料庫:")
timestamp=tools.TimeDate.get_timestamp('%d%H%M%S%f')
dataGroupId = 'roc{}'.format(timestamp)
linkedSize=5
result=utb.saveGraphData(dataGroupId=dataGroupId,linkedSize=linkedSize,linkedNum=10)
startLable='Tag_'+dataGroupId+"_0"
maxLevel=random.randint(2,linkedSize)
targetLable='Tag_'+dataGroupId+"_{}".format(maxLevel-1)
#time.sleep(1)
utb.findListByNeo4j(startLable,maxLevel,targetLable)
def test_crossServiceLoopByDeep():
flag=random.randint(1,10)
data_dict = utb.crossServiceLoopByDeep(callCount=1,deep=random.randint(1,10))
print(data_dict)
#search()
test_search()
4.2 requests_basic.py request二次封裝,核心轉化模組
from locust import SequentialTaskSet, HttpUser, between, task, tag
from locust import events
from locust.contrib.fasthttp import FastHttpUser
import os, sys
import random
from locust import stats
##修改環境變數路徑
sys_path_root = os.getcwd().split('scripts')[0]
sys_path_scripts = sys_path_root + "scripts" #因整個工程有個框架結構 scripts,把此處加入到環境變數,保證locust 命令cmd中可用
sys.path.extend((sys_path_root, sys_path_scripts))
from utils.logger import log
from scripts.WisdomTraining.cases.locustFile.ut.UT_basic import utb,my_request
#from .UT_basic import utb,my_request #同級下,
from locust import events
from gevent._semaphore import Semaphore
all_locusts_spawned = Semaphore() #對協程進行管理
all_locusts_spawned.acquire()
def on_hatch_complete(environment,user_count=100,**kwargs):
"""
對啟動使用者進行集合點設定
適用於場景如:總使用者1000,每秒啟動使用者數1000(注意user_count引數)
:param environment: 當前程式的環境 可以用用 self.user.environment 拿取
:param user_count: 當前啟動的執行緒(使用者數)大於user_count 時才會發起http請求(啟動時設定集合點)
:param kwargs:
:return:
"""
userCount=environment.runner.user_count
log.info("當前啟動使用者數:{}".format(userCount))
if userCount>=user_count:
all_locusts_spawned.release() #建立鉤子方法
print("[環境已準備好]當前啟動使用者數:", userCount)
else:
all_locusts_spawned.wait()
class LocustCount():
"""
統計locust 相關使用,一種資料共享方式
"""
times=0
class TaskSetUT(SequentialTaskSet):
# 類繼承SequentialTaskSet 或 TaskSet類
# 當類裡面的任務請求有先後順序時,繼承SequentialTaskSet類,
# 沒有先後順序,可以使用繼承TaskSet類
pageIndex = 0
pageSize = 20
def on_start(self):
[print(('on_start:',s)) for s in [self.user.environment.stats.total]]
my_request_self=my_request.get_locust_client_dict(self.client) #替換reqeust的 session 為locust_client的session
my_request_self.locust_name_flag=0 #設定locust 請求的 name 屬性引數,url中帶問號
#log.info("共享資料的環境:",self.user.environment)
log.info("共享資料的環境 stats:", self.user.environment.stats.total)
#log.info("開始統計資料 stats_history_csv:", stats.stats_history_csv(self.user.environment))
#utb.wt_b.login_WT()
on_hatch_complete(self.user.environment, user_count=1) #啟動時設定1000個使用者已經準備好
log.info("開始測試了,當前使用者為:", self.user.environment.runner.user_count)
def on_stop(self):
[print('on_stop:',s) for s in [self.user.environment.stats.total]]
pass
@task(1)
def test_RecordData(self):
dataSize = random.randint(1, 100)
result=utb.mysql_saveList(dataSize)
@task(1)
def test_getGlobalTime(self):
result = utb.getGlobalTime()
@task(1)
@tag("leave_1")
def test_search(self):
search_value = random.randint(1,10)
filter = [
{"operation": "like", "alias": "", "dataType": "", "fieldname": "indexInGroup", "name": "indexInGroup",
"value": "{}%".format(search_value)}]
filter = str(filter).replace("'", '"')
pageIndex = self.pageIndex
pageSize = self.pageSize
data_dict = utb.search(filter=filter, pageIndex=pageIndex, pageSize=pageSize)
self.pageIndex += 1
self.pageSize *= self.pageIndex
try:
if data_dict['totalPages'] <= pageIndex + 1:
self.pageIndex = 0
if pageSize >= data_dict['total']:
self.pageSize = random.randint(pageIndex, data_dict['total'])
except Exception as e:
print(str(e))
self.pageIndex = 0
self.pageSize = 20
print('{} test_search :/n'.format(pageIndex), self.pageIndex, self.pageSize)
@task(2)
def test_search_new(self):
filter =''
data_dict = utb.search(filter=filter, pageIndex=0, pageSize=200)
@task(1)
def test_crossServiceLoopByDeep(self):
LocustCount.times+=1
callCount=LocustCount.times
flag=random.randint(1,10)
data_dict = utb.crossServiceLoopByDeep(callCount=callCount,deep=random.randint(1,10))
# This is the HttpUser class.
class UserBehavior(HttpUser): # HttpUser FastHttpUser
tasks = [TaskSetUT]
times = 1
wait_time = between(0, 0)
network_timeout = 600
connection_timeout = 600
print("UserBehavior:測試")
share_data = ['url1', 'url2', 'url3', 'url4', 'url5']
if __name__ == '__main__':
import subprocess,os
#log.delete_log_report_file()
#utb.url_basic = 'http://10.2.1.95:9900'
utb.url_basic = 'http://10.2.1.150:9900'
#utb.url_basic = 'http://10.2.1.150:8533'
path = os.path.dirname(os.path.abspath(__file__))
file_name = os.path.split(__file__)[-1].split(".")[0]
default_url=utb.url_basic
print(path,file_name)
print("開始執行wt") # --no-web -c 2 -r 1 -t 3s
#locust -f --headless -u 1000 -r 100 --run-time 1h30m --step-load --step-users 300 --step-time 20m
# subprocess.call(
# 'locust -f {}/{}.py -u 1 -r 1 -t 10 -l --csv-full-history'.format(path,file_name, default_url),
# shell=True)
cmd ='locust -f {}/{}.py --host={} --web-host="127.0.0.1" --web-port 8090 --csv CSV_{}'.format(path,file_name, default_url,file_name)
print("cmd:",cmd)
dd=subprocess.call(cmd,shell=True) ##--web-port 8090
#d=subprocess.check_call('locust -f {}/{}.py --worker'.format(path,file_name, default_url),shell=True)
# d1=subprocess.check_call('locust -f {}/{}.py --worker'.format(path,file_name, default_url),shell=True)
d2 = subprocess.call('locust -f {}/{}.py --master --host={} --web-host="127.0.0.1" --web-port 8090 --csv CSV_{}'.format(path,file_name,default_url,file_name),shell=True)
4.3 貼圖效果如下:
五、缺陷不足
1、分散式資料不太好統計
2、要多臺電腦執行,是否可以用一個指令碼或者工具進行遠端控制(一鍵命令式)
3、請大家在使用中進一步提出更好的建議
六、其他說明
####6.1 說明
歡迎大家提建議轉載分享,請大家帶上原文連結,改文目前僅發表於TesterHome
6.2 收集的locust其他相關資料
0、官方文件
https://docs.locust.io/en/stable/installation.html
1、新增集合點:
https://testerhome.com/topics/12126
2、資料的幾種方式
https://blog.csdn.net/gogoboi_jin/article/details/79229570
https://www.cnblogs.com/changqing8023/p/9563364.html
3、資料的使用
https://debugtalk.com/post/head-first-locust-advanced-script/
4、locust 原理介紹 與原始碼
https://www.cnblogs.com/belle-ls/p/10487597.html
https://cloud.tencent.com/developer/article/1506669
https://testerhome.com/topics/11829
5、統計效能資料 與優化
http://www.testqa.cn/article/detail/241
http://www.testqa.cn/article/detail/236
6、停止 locust
https://stackoverflow.com/questions/60163341/stop-locust-after-specific-number-of-requests
相關文章
- JMeter 介面自動化測試(手工轉自動化指令碼)JMeter指令碼
- 用Python開發自動化測試指令碼Python指令碼
- 介面自動化測試錄製工具,讓python selenium自動化測試指令碼開發更加方便Python指令碼
- 效能測試——壓測工具locust——指令碼初步編寫指令碼
- python效能測試指令碼Python指令碼
- Android 自動化測試及效能資料採集的 Python 指令碼AndroidPython指令碼
- 《軟體自動化測試成功之道》節選12 - 自動化測試指令碼的維護指令碼
- [Mysql]效能測試指令碼MySql指令碼
- 介面測試(apipost、jmeter和python指令碼)——測試工具APIJMeterPython指令碼
- web自動化測試框架-06 如何快速編寫自動化指令碼Web框架指令碼
- PYTHON測試指令碼Python指令碼
- python 介面自動化測試Python
- 使用 Playwright 指令碼錄製簡化自動化測試:完全指南指令碼
- 介面測試 (apipost、jmeter 和 python 指令碼)APIJMeterPython指令碼
- 介面測試(apipost、jmeter和python指令碼)APIJMeterPython指令碼
- 介面自動化測試
- AutoRunner介面自動化測試工具不能錄製指令碼的解決辦法(A)指令碼
- 測試開發之自動化篇-Appium指令碼開發APP指令碼
- iOS17 效能測試指令碼iOS指令碼
- 請問大家,自動化測試可以實現一個指令碼測試全部平臺嗎?指令碼
- Shell指令碼 | 效能測試之啟動時間指令碼
- 功能測試、自動化測試、效能測試的區別
- web自動化測試框架-02 快速開發用例文件指令碼Web框架指令碼
- 自動化測試系列 —— UI自動化測試UI
- ? python 介面自動化 (二)--什麼是介面測試、為什麼要做介面測試 (詳解)Python
- 如何實現工具無關化?關於自動化測試指令碼的設計指令碼
- python自動化測試Python
- 介面自動化測試框架 HttpFPT框架HTTP
- 二、介面自動化測試(2)
- 壓力測試指令碼指令碼
- Jmeter+Ant+Python 介面自動化測試JMeterPython
- 軟體測試(功能、介面、效能、自動化)詳解
- Linux系統效能測試指令碼(unixbenchnmon)Linux指令碼
- LoadRunner長連線效能測試指令碼指令碼
- 如何用 JMeter 編寫效能測試指令碼?JMeter指令碼
- 使用jmeter+ant進行介面自動化測試(資料驅動)之一:設計jmeter指令碼JMeter指令碼
- 【自動化測試入門】自動化測試思維
- 效能測試工具Locust