forked from DxvLwRYF/apiAutoTest
优化用例格式,将上传文件代码进行优化封装
This commit is contained in:
parent
0192f8aeca
commit
24bcce71e0
11
README.md
11
README.md
|
@ -82,11 +82,12 @@
|
|||
|
||||
#### 安装教程
|
||||
|
||||
1. git clone https://gitee.com/zy7y/apiAutoTest.git
|
||||
2. 使用pycharm打开项目使用Terminal 输入 python3 -m venv venv 新建虚拟环境
|
||||
3. 执行pip install -r requirements.txt 安装依赖库
|
||||
4. 修改config.ymal文件中email文件配置收件人邮箱,授权码,发件人邮箱
|
||||
5. 运行/test/test_api.py 文件
|
||||
1. git clone https://gitee.com/zy7y/apiAutoTest.git / https://github.com/zy7y/apiAutoTest.git
|
||||
2. 安装Java与allure,https://www.cnblogs.com/zy7y/p/13403699.html
|
||||
3. 使用pycharm打开项目使用Terminal 输入 python3 -m venv venv 新建虚拟环境 (可选)
|
||||
4. 执行pip install -r requirements.txt 安装依赖库(若下载超时:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package)
|
||||
5. 修改config.ymal文件中email文件配置收件人邮箱,授权码,发件人邮箱
|
||||
6. 运行/test/test_api.py 文件
|
||||
#### 运行测试前修改
|
||||
首先确保需要的环境与依赖包无问题之后,使用Pycharm打开项目,找到`settings`修改为unitest或者其他非pytest,具体操作如下
|
||||
[![B21lr9.md.jpg](https://s1.ax1x.com/2020/11/05/B21lr9.md.jpg)](https://imgchr.com/i/B21lr9)
|
||||
|
|
|
@ -12,7 +12,7 @@ FastAPI官网 https://fastapi.tiangolo.com/zh/tutorial/request-files/
|
|||
|
||||
from typing import List
|
||||
|
||||
from fastapi import FastAPI, File, UploadFile, Form
|
||||
from fastapi import FastAPI, File, UploadFile
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
@ -25,7 +25,7 @@ async def create_upload_file(file_excel: UploadFile = File(...)):
|
|||
# 保存本地
|
||||
with open(file_excel.filename, "wb") as f:
|
||||
f.write(contents)
|
||||
return {'msg': '操作成功', "filename": file_excel.filename, 'username': username, "meta": {"msg": "ok"}}
|
||||
return {'msg': '操作成功', "filename": file_excel.filename, "meta": {"msg": "ok"}}
|
||||
|
||||
|
||||
@app.post("/upload_files/", name='上传多个文件')
|
||||
|
@ -41,6 +41,6 @@ async def create_upload_files(files: List[UploadFile] = File(...)):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 启动项目后 访问 http://127.0.0.1:8000/docs 可查看接口文档
|
||||
# 启动项目后 访问 http://127.0.0.1:8888/docs 可查看接口文档
|
||||
import uvicorn
|
||||
uvicorn.run('api:app', reload=True)
|
||||
uvicorn.run('api:app', reload=True, port=8888)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
|
@ -1,5 +1,6 @@
|
|||
server:
|
||||
test: http://127.0.0.1:8000
|
||||
# 本地接口服务
|
||||
test: http://127.0.0.1:8888/
|
||||
# https://space.bilibili.com/283273603 演示项目后端服务来自
|
||||
dev: http://www.ysqorz.top:8888/api/private/v1/
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,35 +1,11 @@
|
|||
allure-pytest==2.8.17
|
||||
allure-python-commons==2.8.17
|
||||
atomicwrites==1.4.0
|
||||
attrs==20.3.0
|
||||
certifi==2020.11.8
|
||||
chardet==3.0.4
|
||||
click==7.1.2
|
||||
colorama==0.4.4
|
||||
fastapi==0.61.2
|
||||
h11==0.11.0
|
||||
idna==2.10
|
||||
importlib-metadata==2.0.0
|
||||
iniconfig==1.1.1
|
||||
jsonpath==0.82
|
||||
loguru==0.5.1
|
||||
more-itertools==8.6.0
|
||||
packaging==20.4
|
||||
pluggy==0.13.1
|
||||
py==1.9.0
|
||||
pydantic==1.7.2
|
||||
pyparsing==2.4.7
|
||||
pytest==6.0.1
|
||||
python-multipart==0.0.5
|
||||
PyYAML==5.3.1
|
||||
requests==2.24.0
|
||||
six==1.15.0
|
||||
starlette==0.13.6
|
||||
toml==0.10.2
|
||||
typing-extensions==3.7.4.3
|
||||
urllib3==1.25.11
|
||||
uvicorn==0.12.2
|
||||
win32-setctime==1.0.3
|
||||
xlrd==1.2.0
|
||||
yagmail==0.11.224
|
||||
zipp==3.1.0
|
||||
uvicorn==0.12.2
|
||||
fastapi==0.61.2
|
||||
python-multipart==0.0.5
|
|
@ -19,7 +19,7 @@ from tools.read_data import ReadData
|
|||
|
||||
# 读取配置文件 对象
|
||||
rc = ReadConfig()
|
||||
base_url = rc.read_serve_config('test')
|
||||
base_url = rc.read_serve_config('dev')
|
||||
token_reg, res_reg = rc.read_response_reg()
|
||||
report_data = rc.read_file_path('report_data')
|
||||
report_generate = rc.read_file_path('report_generate')
|
||||
|
@ -49,9 +49,9 @@ class TestApiAuto(object):
|
|||
# os.system(f'allure serve {report_data}')
|
||||
logger.warning('报告已生成')
|
||||
|
||||
@pytest.mark.parametrize('case_number,case_title,path,is_token,method,parametric_key,file_var,'
|
||||
@pytest.mark.parametrize('case_number,case_title,path,is_token,method,parametric_key,file_obj,'
|
||||
'data,expect', data_list)
|
||||
def test_main(self, case_number, case_title, path, is_token, method, parametric_key, file_var,
|
||||
def test_main(self, case_number, case_title, path, is_token, method, parametric_key, file_obj,
|
||||
data, expect):
|
||||
|
||||
# 感谢:https://www.cnblogs.com/yoyoketang/p/13386145.html,提供动态添加标题的实例代码
|
||||
|
@ -70,7 +70,7 @@ class TestApiAuto(object):
|
|||
|
||||
with allure.step("发送请求,取得响应结果的json串"):
|
||||
allure.attach(json.dumps(base_url + path, ensure_ascii=False, indent=4), "最终请求地址", allure.attachment_type.TEXT)
|
||||
res = br.api_send(method=method, url=base_url + path, parametric_key=parametric_key, file_obj=file_var,
|
||||
res = br.api_send(method=method, url=base_url + path, parametric_key=parametric_key, file_obj=file_obj,
|
||||
data=data, header=header)
|
||||
allure.attach(json.dumps(res, ensure_ascii=False, indent=4), "实际响应", allure.attachment_type.TEXT)
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
@time: 2020/7/31
|
||||
"""
|
||||
import json
|
||||
import re
|
||||
|
||||
import allure
|
||||
|
||||
from jsonpath import jsonpath
|
||||
|
@ -28,6 +30,20 @@ def extractor(obj: dict, expr: str = '.') -> object:
|
|||
return result
|
||||
|
||||
|
||||
def rep_expr(content: str, data: dict, expr: str = '&(.*?)&') -> str:
|
||||
"""从请求参数的字符串中,使用正则的方法找出合适的字符串内容并进行替换
|
||||
:param content: 原始的字符串内容
|
||||
:param data: 在该项目中一般为响应字典,从字典取值出来
|
||||
:param expr: 查找用的正则表达式
|
||||
return content: 替换表达式后的字符串
|
||||
"""
|
||||
logger.info(f'替换前内容{content}')
|
||||
for ctt in re.findall(expr, content):
|
||||
content = content.replace(f'&{ctt}&', str(extractor(data, ctt)))
|
||||
logger.info(f'替换后内容{content}')
|
||||
return content
|
||||
|
||||
|
||||
def convert_json(dict_str: str) -> dict:
|
||||
"""
|
||||
:param dict_str: 长得像字典的字符串
|
||||
|
@ -40,10 +56,18 @@ def convert_json(dict_str: str) -> dict:
|
|||
dict_str = dict_str.replace('True', 'true')
|
||||
elif 'False' in dict_str:
|
||||
dict_str = dict_str.replace('False', 'false')
|
||||
return json.loads(dict_str)
|
||||
dict_str = json.loads(dict_str)
|
||||
except Exception as e:
|
||||
logger.error(f'{e}, json.loads转字典失败')
|
||||
return eval(dict_str)
|
||||
if 'null' in dict_str:
|
||||
dict_str = dict_str.replace('null', 'None')
|
||||
elif 'true' in dict_str:
|
||||
dict_str = dict_str.replace('true', 'True')
|
||||
elif 'False' in dict_str:
|
||||
dict_str = dict_str.replace('false', 'False')
|
||||
dict_str = eval(dict_str)
|
||||
logger.error(e)
|
||||
logger.info(f'{dict_str}, {type(dict_str)}')
|
||||
return dict_str
|
||||
|
||||
|
||||
def allure_title(title: str) -> None:
|
||||
|
@ -51,14 +75,14 @@ def allure_title(title: str) -> None:
|
|||
allure.dynamic.title(title)
|
||||
|
||||
|
||||
def allure_step(step: str, title: object, var: str) -> None:
|
||||
def allure_step(step: str, var: str) -> None:
|
||||
"""
|
||||
:param step: 步骤名称
|
||||
:param title: 附件标题
|
||||
:param step: 步骤及附件名称
|
||||
:param var: 附件内容
|
||||
"""
|
||||
with allure.step(step):
|
||||
allure.attach(json.dumps(var, ensure_ascii=False, indent=4), title, allure.attachment_type.TEXT)
|
||||
allure.attach(json.dumps(var, ensure_ascii=False, indent=4), step, allure.attachment_type.TEXT)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(convert_json('["1","2"]'))
|
|
@ -7,8 +7,6 @@
|
|||
@ide: PyCharm
|
||||
@time: 2020/11/18
|
||||
"""
|
||||
import json
|
||||
import re
|
||||
from tools import *
|
||||
|
||||
|
||||
|
@ -28,17 +26,14 @@ class DataProcess:
|
|||
logger.info(f'添加key: {key}, 对应value: {value}')
|
||||
|
||||
@classmethod
|
||||
def handle_path(cls, path_str: str = '') -> str:
|
||||
def handle_path(cls, path_str: str) -> str:
|
||||
"""路径参数处理
|
||||
:param path_str: 带提取表达式的字符串 /&$.case_005.data.id&/state/&$.case_005.data.create_time&
|
||||
上述内容表示,从响应字典中提取到case_005字典里data字典里id的值,假设是500,后面&$.case_005.data.create_time& 类似,最终提取结果
|
||||
return /511/state/1605711095
|
||||
"""
|
||||
# /&$.case.data.id&/state/&$.case_005.data.create_time&
|
||||
for i in re.findall('&(.*?)&', path_str):
|
||||
path_str = path_str.replace(f'&{i}&', str(extractor(cls.response_dict, i)))
|
||||
logger.info(f'提取出的路径地址: {path_str}')
|
||||
return path_str
|
||||
return rep_expr(path_str, cls.response_dict)
|
||||
|
||||
@classmethod
|
||||
def handle_header(cls, is_token: str, response: dict, reg) -> dict:
|
||||
|
@ -60,17 +55,15 @@ class DataProcess:
|
|||
# todo 待完成
|
||||
if file_obj == '':
|
||||
return None
|
||||
file_var = file_obj.split(':')[0]
|
||||
file_path = file_obj.split(':')[1]
|
||||
if file_path.startswith('[') and file_path.endswith(']'):
|
||||
file_path_list = convert_json(file_path)
|
||||
files = []
|
||||
for k, v in convert_json(file_obj).items():
|
||||
# 多文件上传
|
||||
for file_path in file_path_list:
|
||||
files.append((file_var, (open(file_path, 'rb'))))
|
||||
else:
|
||||
# 单文件上传
|
||||
files = {file_var: open(file_path, 'rb')}
|
||||
if isinstance(v, list):
|
||||
files = []
|
||||
for path in v:
|
||||
files.append((k, (open(path, 'rb'))))
|
||||
else:
|
||||
# 单文件上传
|
||||
files = {k: open(v, 'rb')}
|
||||
return files
|
||||
|
||||
@classmethod
|
||||
|
@ -81,11 +74,13 @@ class DataProcess:
|
|||
"""
|
||||
if variable == '':
|
||||
return
|
||||
for i in re.findall('&(.*?)&', variable):
|
||||
variable = variable.replace(f'&{i}&', str(extractor(cls.response_dict, i)))
|
||||
variable = convert_json(variable)
|
||||
data = rep_expr(variable, cls.response_dict)
|
||||
variable = convert_json(data)
|
||||
logger.info(f'最终的请求数据如下: {variable}')
|
||||
return variable
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(convert_json("""{"files":["D:\\apiAutoTest\\data\\case_data - 副本.xls", "D:\\apiAutoTest\\data\\case_data.xlsx"]}"""))
|
Loading…
Reference in New Issue