This commit is contained in:
zy7y 2020-11-20 20:09:12 +08:00
parent e913714fbd
commit 7c41b18b87
8 changed files with 146 additions and 36 deletions

View File

@ -10,6 +10,8 @@
from loguru import logger
import requests
from tools import convert_json
from tools.data_process import DataProcess
from tools.read_data import ReadData
@ -20,7 +22,7 @@ class BaseRequest(object):
self.session = requests.Session()
# 请求
def send_requests(self, method, url, parametric_key=None, data=None, file_var=None, file_path=None, header=None):
def api_send(self, method, url, parametric_key=None, data=None, file_obj=None, header=None):
"""
:param method: 请求方法
@ -29,8 +31,7 @@ class BaseRequest(object):
post/put/patch请求可使用jsonapplication/json/data
:param data: 参数数据默认等于None
:param file_var: 接口中接受文件的参数关键字
:param file_path: 文件对象的地址 单个文件直接放地址/Users/zy7y/Desktop/vue.js
:param file_obj: 文件对象的地址 单个文件直接放地址/Users/zy7y/Desktop/vue.js
多个文件格式["/Users/zy7y/Desktop/vue.js","/Users/zy7y/Desktop/jenkins.war"]
:param header: 请求头
:return: 返回json格式的响应
@ -38,19 +39,8 @@ class BaseRequest(object):
# 修改时间2020年9月14日17:09
session = self.session
if (file_var in [None, '']) and (file_path in [None, '']):
files = None
else:
# 文件不为空的操作
if file_path.startswith('[') and file_path.endswith(']'):
file_path_list = eval(file_path)
files = []
# 多文件上传
for file_path in file_path_list:
files.append((file_var, (open(file_path, 'rb'))))
else:
# 单文件上传
files = {file_var: open(file_path, 'rb')}
files = DataProcess.handler_files(file_obj)
if parametric_key == 'params':
res = session.request(method=method, url=url, params=data, headers=header)
elif parametric_key == 'data':
@ -61,4 +51,16 @@ class BaseRequest(object):
raise ValueError(
'可选关键字为get/delete/head/options/请求使用params, post/put/patch请求可使用jsonapplication/json/data')
logger.info(f'请求方法:{method},请求路径:{url}, 请求参数:{data}, 请求文件:{files}, 请求头:{header})')
return res.json()
return res.json()
def api_front(self):
"""请求api的前置处理方法"""
pass
def api_position(self):
"""请求api的后置处理方法"""
pass

10
api_server/__init__.py Normal file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: apiAutoTest
@author: zy7y
@file: __init__.py
@ide: PyCharm
@time: 2020/11/20
@desc: 提供一些测试用的api接口接口代码 请前往FastAPI官网查看学习
"""

46
api_server/api.py Normal file
View File

@ -0,0 +1,46 @@
#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: apiAutoTest
@author: zy7y
@file: api.py
@ide: PyCharm
@time: 2020/11/20
@desc: 上传文件接口服务,用于调试上传文件接口处理方法源码来自
FastAPI官网 https://fastapi.tiangolo.com/zh/tutorial/request-files/
"""
from typing import List
from fastapi import FastAPI, File, UploadFile, Form
app = FastAPI()
@app.post("/upload_file/", name='上传单文件接口')
async def create_upload_file(file_excel: UploadFile = File(...)):
# 单文件上传接口,并将文件写到服务器地址, 接收文件对象的参数 是 file_excel
# 读取文件
contents = await file_excel.read()
# 保存本地
with open(file_excel.filename, "wb") as f:
f.write(contents)
return {'msg': '操作成功', "filename": file_excel.filename, 'username': username, "meta": {"msg": "ok"}}
@app.post("/upload_files/", name='上传多个文件')
async def create_upload_files(files: List[UploadFile] = File(...)):
# 多文件上传接口,并将文件写到服务器, 接收文件对象的参数 是 files
for file in files:
# 读取文件
contents = await file.read()
# 保存本地
with open(file.filename, "wb") as f:
f.write(contents)
return {"filenames": [file.filename for file in files], "meta": {"msg": "ok"}}
if __name__ == '__main__':
# 启动项目后 访问 http://127.0.0.1:8000/docs 可查看接口文档
import uvicorn
uvicorn.run('api:app', reload=True)

View File

@ -1,5 +1,5 @@
server:
test: http://127.0.0.1:8888/api/private/v1/
test: http://127.0.0.1:8000
# https://space.bilibili.com/283273603 演示项目后端服务来自
dev: http://www.ysqorz.top:8888/api/private/v1/

View File

@ -1,9 +1,35 @@
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
zipp==3.1.0

View File

@ -19,7 +19,7 @@ from tools.read_data import ReadData
# 读取配置文件 对象
rc = ReadConfig()
base_url = rc.read_serve_config('dev')
base_url = rc.read_serve_config('test')
token_reg, res_reg = rc.read_response_reg()
report_data = rc.read_file_path('report_data')
report_generate = rc.read_file_path('report_generate')
@ -43,16 +43,16 @@ class TestApiAuto(object):
logger.add(log_path, encoding='utf-8')
pytest.main(args=[f'--alluredir={report_data}'])
# 本地生成 allure 报告文件,需注意 不用pycharm等类似ide 打开会出现无数据情况
# os.system(f'allure generate {report_data} -o {report_generate} --clean')
os.system(f'allure generate {report_data} -o {report_generate} --clean')
# 直接启动allure报告会占用一个进程建立一个本地服务并且自动打开浏览器访问ps 程序不会自动结束,需要自己去关闭)
os.system(f'allure serve {report_data}')
# os.system(f'allure serve {report_data}')
logger.warning('报告已生成')
@pytest.mark.parametrize('case_number,case_title,path,is_token,method,parametric_key,file_var,'
'file_path,data,expect', data_list)
'data,expect', data_list)
def test_main(self, case_number, case_title, path, is_token, method, parametric_key, file_var,
file_path, data, expect):
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.send_requests(method=method, url=base_url + path, parametric_key=parametric_key, file_var=file_var, file_path=file_path,
res = br.api_send(method=method, url=base_url + path, parametric_key=parametric_key, file_obj=file_var,
data=data, header=header)
allure.attach(json.dumps(res, ensure_ascii=False, indent=4), "实际响应", allure.attachment_type.TEXT)

View File

@ -33,13 +33,17 @@ def convert_json(dict_str: str) -> dict:
:param dict_str: 长得像字典的字符串
return json格式的内容
"""
if 'None' in dict_str:
dict_str = dict_str.replace('None', 'null')
elif 'True' in dict_str:
dict_str = dict_str.replace('True', 'true')
elif 'False' in dict_str:
dict_str = dict_str.replace('False', 'false')
return json.loads(dict_str)
try:
if 'None' in dict_str:
dict_str = dict_str.replace('None', 'null')
elif 'True' in dict_str:
dict_str = dict_str.replace('True', 'true')
elif 'False' in dict_str:
dict_str = dict_str.replace('False', 'false')
return json.loads(dict_str)
except Exception as e:
logger.error(f'{e} json.loads转字典失败')
return eval(dict_str)
def allure_title(title: str) -> None:
@ -56,8 +60,5 @@ def allure_step(step: str, title: object, var: str) -> None:
with allure.step(step):
allure.attach(json.dumps(var, ensure_ascii=False, indent=4), title, allure.attachment_type.TEXT)
if __name__ == '__main__':
r = json.dumps('')
print(r)
print(convert_json('["1","2"]'))

View File

@ -51,6 +51,28 @@ class DataProcess:
else:
return cls.header
@classmethod
def handler_files(cls, file_obj: str) -> object:
"""file对象处理方法
:param file_obj: 上传文件使用格式接口中文件参数的名称:"文件路径地址"/["文件地址1", "文件地址2"]
实例- 单个文件: &file&D:
"""
# 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 file_path in file_path_list:
files.append((file_var, (open(file_path, 'rb'))))
else:
# 单文件上传
files = {file_var: open(file_path, 'rb')}
return files
@classmethod
def handle_data(cls, variable: str) -> dict:
"""请求数据处理
@ -64,3 +86,6 @@ class DataProcess:
variable = convert_json(variable)
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"]}"""))