修复查询字符串为空字符时引发的bug

This commit is contained in:
aaronchenyongzhi 2023-09-14 04:01:25 +08:00
parent 09bcbd2fd0
commit 7a0e17b104
11 changed files with 688 additions and 362 deletions

File diff suppressed because one or more lines are too long

View File

@ -39,7 +39,7 @@ def gen_random_num(length):
Returns:
"""
return random.randint(int('1' + '0' * (length - 1)), int('9' * length))
return random.randint(int('1' + '0' * (int(length) - 1)), int('9' * int(length)))
@logger.log_decorator()

View File

@ -83,9 +83,9 @@ class Action(Extractor, LoadScript, Validator, EncryptData):
"""执行断言校验"""
expected = self.replace_dependent_parameter(expected)
try:
res = self.run_validate(expected, self.response_json)
self.run_validate(expected, self.response_json)
# 如果不填写断言,则自动断言状态码
if res is None:
if not expected:
from common.validation.comparators import eq
eq(200, self.response.status_code)
result = "PASS"

View File

@ -123,6 +123,7 @@ if __name__ == '__main__':
"ft": "{{fk().ean(length=13)}}",
"st": "{{ms_fmt_hms(2000)}}",
"time": "{{random_id_card()}}",
"gen_random_num": "{{gen_random_num(5)}}",
"x":'{"a":"b","c":"{{get_timestamp()}}"}'
}
ret = loader.replace_dependent_parameter(dat)

View File

@ -24,92 +24,92 @@ from common.utils.exceptions import ResponseJsonConversionError
class HttpClient(LoadModulesFromFolder):
session = requests.Session()
def __init__(self):
super().__init__()
self.request = None
self.response = None
self.response_json = None
self.files = []
@request_retry_on_exception()
def http_client(self, host, url, method, **kwargs):
"""
发送 http 请求
@param host: 域名
@param url: 接口 __url
@param method: http 请求方法
@param kwargs: 接受 requests 原生的关键字参数
@return: 响应对象
"""
# 关闭 https 警告信息
urllib3.disable_warnings()
kwargs = self.processing_data(host, url, method, **kwargs)
# 发送请求
self.request = requests.Request(**kwargs)
self.response = self.session.send(self.request.prepare(), timeout=(15, 20), verify=True)
# 关闭文件
[i.close() for i in self.files if len(self.files) > 0]
self.post_response()
return self.response
def processing_data(self, host, url, method, **kwargs):
kwargs["method"] = method
if not url:
raise ValueError("URL cannot be None")
__url = f'{host}{url}' if not re.match(r"https?", url) else url
kwargs["url"] = __url
# 兼容处理 headers 参数为字符串类型的情况
if 'headers' in kwargs and isinstance(kwargs['headers'], str):
kwargs['headers'] = json.loads(kwargs['headers'])
# 兼容处理 json 参数为字符串类型的情况
if 'json' in kwargs and isinstance(kwargs['json'], str):
kwargs['json'] = json.loads(kwargs['json'])
kwargs['params'] = json.loads(kwargs['params']) if isinstance(kwargs['params'], str) else None
# 处理 files 参数的情况
if 'files' in kwargs:
file_paths = kwargs['files']
if isinstance(file_paths, str):
file_paths = json.loads(file_paths)
files = []
file_utils = FileUtils()
for i, file_path in enumerate(file_paths):
file_type = mimetypes.guess_type(file_path)[0]
file_path_completion = file_utils.get_file_path(file_path)
f = open(file_path_completion, 'rb')
self.files.append(f)
files.append(
('file', (f'{file_path}', f, file_type))
)
kwargs['files'] = files
return kwargs
def post_response(self):
# 处理响应结果
self.update_environments("responseStatusCode", self.response.status_code)
self.update_environments("responseTime", round(self.response.elapsed.total_seconds() * 1000, 2))
try:
self.response_json = self.response.json()
except Exception as e:
ResponseJsonConversionError(self.response.text, str(e))
self.response_json = None
session = requests.Session()
def __init__(self):
super().__init__()
self.request = None
self.response = None
self.response_json = None
self.files = []
@request_retry_on_exception()
def http_client(self, host, url, method, **kwargs):
"""
发送 http 请求
@param host: 域名
@param url: 接口 __url
@param method: http 请求方法
@param kwargs: 接受 requests 原生的关键字参数
@return: 响应对象
"""
# 关闭 https 警告信息
urllib3.disable_warnings()
kwargs = self.processing_data(host, url, method, **kwargs)
# 发送请求
self.request = requests.Request(**kwargs)
self.response = self.session.send(self.request.prepare(), timeout=(15, 20), verify=True)
# 关闭文件
[i.close() for i in self.files if len(self.files) > 0]
self.post_response()
return self.response
def processing_data(self, host, url, method, **kwargs):
kwargs["method"] = method.lower()
if not url:
raise ValueError("URL cannot be None")
__url = f'{host}{url}' if not re.match(r"https?", url) else url
kwargs["url"] = __url
# 兼容处理 headers 参数为字符串类型的情况
if 'headers' in kwargs and isinstance(kwargs['headers'], str):
kwargs['headers'] = json.loads(kwargs['headers'])
# 兼容处理 json 参数为字符串类型的情况
if 'json' in kwargs and isinstance(kwargs['json'], str):
kwargs['json'] = json.loads(kwargs['json'])
kwargs['params'] = json.loads(kwargs['params']) if isinstance(kwargs['params'], str) and kwargs[
'params'] else None
# 处理 files 参数的情况
if 'files' in kwargs:
file_paths = kwargs['files']
if isinstance(file_paths, str):
file_paths = json.loads(file_paths)
files = []
file_utils = FileUtils()
for i, file_path in enumerate(file_paths):
file_type = mimetypes.guess_type(file_path)[0]
file_path_completion = file_utils.get_file_path(file_path)
f = open(file_path_completion, 'rb')
self.files.append(f)
files.append(
('file', (f'{file_path}', f, file_type))
)
kwargs['files'] = files
return kwargs
def post_response(self):
# 处理响应结果
self.update_environments("responseStatusCode", self.response.status_code)
self.update_environments("responseTime", round(self.response.elapsed.total_seconds() * 1000, 2))
try:
self.response_json = self.response.json()
except Exception as e:
ResponseJsonConversionError(self.response.text, str(e))
self.response_json = None
if __name__ == '__main__':
hst = 'https://kkk.ll.com'
ul = '/bsp/test/'
meth = 'post'
kwarg = {
'headers': {},
'data': {},
'files': ['test.txt']
}
pyt = HttpClient()
pyt.http_client(hst, ul, meth, **kwarg)
hst = 'https://kkk.ll.com'
ul = '/bsp/test/'
meth = 'post'
kwarg = {
'headers': {},
'data': {},
'files': ['test.txt']
}
pyt = HttpClient()
pyt.http_client(hst, ul, meth, **kwarg)

View File

@ -16,7 +16,7 @@ from common.file_handling.file_utils import FileUtils
id_count = 0
result = []
# 兼容 postman 中存在 {{xxx}} 不带双引号会导致反序列化失败的情景,将不带双引号的强制带上双引号!
pattern = r'(?<="): (\{\{[^}]+\}\})(?=,|\s*\n*\s*[\}\]])'
pattern = r'(?<="):(\{\{[^}]+\}\})(?=,|\s*\n*\s*[\}\]])'
def replace_match(match):
@ -79,7 +79,7 @@ def parsing_postman(path):
# api请求头
api['Headers'] = json.dumps(header, ensure_ascii=False)
api['HeadersCrypto'] = ''
api['QueryStr'] = ''
api['QueryString'] = ''
body = request.get('body')
if body:
# api接口请求参数类型

View File

@ -19,7 +19,8 @@ class Config:
# 测试数据所在路径
TEMPLATES = os.path.join(PARENT_DIR, "src", "templates", "template.xlsx") # 用例模板文件
TEST_CASE = os.path.join(PARENT_DIR, "src", "cases", "test_cases.xlsx")
TEST_CASE = os.path.join(PARENT_DIR, "src", "cases", "test_openapi_cases.xlsx")
# TEST_CASE = os.path.join(PARENT_DIR, "src", "cases", "test_cases.xlsx")
TEST_FILES = os.path.join(PARENT_DIR, 'src', 'files') # 用来上传文件的文件夹
# 测试用例脚本目录

View File

@ -43,9 +43,9 @@ class ExcelConverter:
if __name__ == '__main__':
postman_to_json = r'.\data\temporary_file\postman.json' # postman导出的json文件
postman_out_file = os.path.join(Config.BASE_URL, 'src', 'test_cases', 'test_postman_cases.xlsx') # 转化后的文件保存的位置
openapi_to_json = r'.\data\temporary_file\openapi.json' # postman导出的json文件
openapi_out_file = os.path.join(Config.BASE_URL, 'src', 'test_cases', 'test_openapi_cases.xlsx') # 转化后的文件保存的位置
postman_to_json = r'.\src\temporary_file\bookShopApi.json' # postman导出的json文件
postman_out_file = os.path.join(Config.PARENT_DIR, 'src', 'cases', 'test_openapi_cases.xlsx') # 转化后的文件保存的位置
# openapi_to_json = r'.\data\temporary_file\openapi.json' # postman导出的json文件
# openapi_out_file = os.path.join(Config.BASE_URL, 'src', 'test_cases', 'test_openapi_cases.xlsx') # 转化后的文件保存的位置
ExcelConverter('postman', postman_to_json, postman_out_file).main()
ExcelConverter('postman', openapi_to_json, openapi_out_file).main()
# ExcelConverter('postman', openapi_to_json, openapi_out_file).main()

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,457 @@
{
"info": {
"_postman_id": "c5447393-7c43-4967-ac19-292724f807c7",
"name": "bookShopApi",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "6288605"
},
"item": [
{
"name": "注册-/api/auth/register",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"kira\",\r\n \"email\": \"kira@163.com\",\r\n \"password\": 123456,\r\n \"password_confirmation\": 123456\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/api/auth/register",
"host": [
"{{HOST}}"
],
"path": [
"api",
"auth",
"register"
]
}
},
"response": []
},
{
"name": "登录-/api/auth/login",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code name has string\", function () {\r",
" let response = pm.response.json();\r",
" pm.environment.set(\"Authorization\", \"Bearer \" + response.access_token)\r",
"\r",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"email\": \"kira@163.com\",\r\n \"password\": 123456\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/api/auth/login",
"host": [
"{{HOST}}"
],
"path": [
"api",
"auth",
"login"
]
}
},
"response": []
},
{
"name": "刷新token-api/auth/refresh",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Status code name has string\", function () {\r",
" let response = pm.response.json();\r",
" pm.environment.set(\"Authorization\", \"Bearer \" + response.access_token)\r",
"\r",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"url": {
"raw": "{{HOST}}/api/auth/refresh",
"host": [
"{{HOST}}"
],
"path": [
"api",
"auth",
"refresh"
]
}
},
"response": []
},
{
"name": "查询商品列表-/api/goods",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Body matches string\", function () {\r",
" let res = pm.response.json()\r",
" pm.environment.set(\"good_id\", res.goods.data[0].id)\r",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"url": {
"raw": "{{HOST}}/api/goods?page=1",
"host": [
"{{HOST}}"
],
"path": [
"api",
"goods"
],
"query": [
{
"key": "page",
"value": "1"
}
]
}
},
"response": []
},
{
"name": "获取商品详情-/api/goods/{{goodId}}",
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"url": {
"raw": "{{HOST}}/api/goods/{{good_id}}",
"host": [
"{{HOST}}"
],
"path": [
"api",
"goods",
"{{good_id}}"
]
}
},
"response": []
},
{
"name": "查看购物车列表-/api/carts",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Body matches string\", function () {\r",
" let res = pm.response.json()\r",
" let good_id = pm.environment.get(\"good_id\")\r",
" console.log(\"good_id\",good_id)\r",
" for (i of res.data) {\r",
" if (i.good_id === good_id) {\r",
" console.log(\"i.id=\", i.id)\r",
" pm.environment.set(\"cart\", i.id)\r",
" }\r",
"\r",
" }\r",
"\r",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"url": {
"raw": "{{HOST}}/api/carts",
"host": [
"{{HOST}}"
],
"path": [
"api",
"carts"
]
}
},
"response": []
},
{
"name": "添加商品进入购物车-/api/carts",
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"goods_id\":\"{{good_id}}\",\r\n \"num\":\"2\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/api/carts",
"host": [
"{{HOST}}"
],
"path": [
"api",
"carts"
]
}
},
"response": []
},
{
"name": "再次查看购物车列表-/api/carts",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Body matches string\", function () {\r",
" let res = pm.response.json()\r",
" let good_id = pm.environment.get(\"good_id\")\r",
" console.log(\"good_id\",good_id)\r",
" for (i of res.data) {\r",
" if (i.goods_id === good_id) {\r",
" console.log(\"i.id=\", i.id)\r",
" pm.environment.set(\"cart\", i.id)\r",
" }\r",
"\r",
" }\r",
"\r",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"url": {
"raw": "{{HOST}}/api/carts",
"host": [
"{{HOST}}"
],
"path": [
"api",
"carts"
]
}
},
"response": []
},
{
"name": "修改购物车商品数量-/api/carts/{{cart}}",
"request": {
"method": "PUT",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"num\": \"6\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/api/carts/{{cart}}",
"host": [
"{{HOST}}"
],
"path": [
"api",
"carts",
"{{cart}}"
]
}
},
"response": []
},
{
"name": "购物车改变选中商品-/api/carts/checked",
"request": {
"method": "PATCH",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"cart_ids\": [\"{{cart}\"]\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/api/carts/checked",
"host": [
"{{HOST}}"
],
"path": [
"api",
"carts",
"checked"
]
}
},
"response": []
},
{
"name": "购物车商品变成预览订单-/api/orders/preview",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Body matches string\", function () {\r",
" let res = pm.response.json();\r",
" pm.environment.set(\"address_id\",res.address[0].id)\r",
"});"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"url": {
"raw": "{{HOST}}/api/orders/preview",
"host": [
"{{HOST}}"
],
"path": [
"api",
"orders",
"preview"
]
}
},
"response": []
},
{
"name": "提交订单-/api/orders",
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "{{Authorization}}",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"address_id\":{{address_id}}\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{HOST}}/api/orders",
"host": [
"{{HOST}}"
],
"path": [
"api",
"orders"
]
}
},
"response": []
}
]
}