Pytest接口自动化如何实现,有什么要注意的
Admin 2022-09-06 群英技术资讯 731 次浏览
这篇文章主要讲解了“Pytest接口自动化如何实现,有什么要注意的”,文中的讲解内容简单、清晰、详细,对大家学习或是工作可能会有一定的帮助,希望大家阅读完这篇文章能有所收获。下面就请大家跟着小编的思路一起来学习一下吧。

解决痛点:
框架使用说明:
pip install -r requirements.txtrun.py文件Excel或者Yaml 文件里面,按照示例编写即可,也可以在test_case 内容介绍下通过python脚本编写casejsonpath、正则表达式提取数据Excel和test_case 内容介绍下用例工具类封装
assert_util.py 断言工具类封装
def assert_result(response: Response, expected: str) -> None:
""" 断言方法
:param response: 实际响应对象
:param expected: 预期响应内容,从excel中或者yaml读取、或者手动传入
return None
"""
if expected is None:
logging.info("当前用例无断言!")
return
if isinstance(expected, str):
expect_dict = eval(expected)
else:
expect_dict = expected
index = 0
for k, v in expect_dict.items():
# 获取需要断言的实际结果部分
for _k, _v in v.items():
if _k == "http_code":
actual = response.status_code
else:
if response_type(response) == "json":
actual = json_extractor(response.json(), _k)
else:
actual = re_extract(response.text, _k)
index += 1
logging.info(f'第{index}个断言数据,实际结果:{actual} | 预期结果:{_v} 断言方式:{k}')
allure_step(f'第{index}个断言数据', f'实际结果:{actual} = 预期结果:{v}')
try:
if k == "eq": # 相等
assert actual == _v
elif k == "in": # 包含关系
assert _v in actual
elif k == "gt": # 判断大于,值应该为数值型
assert actual > _v
elif k == "lt": # 判断小于,值应该为数值型
assert actual < _v
elif k == "not": # 不等于,非
assert actual != _v
else:
logging.exception(f"判断关键字: {k} 错误!")
except AssertionError:
raise AssertionError(f'第{index}个断言失败 -|- 断言方式:{k} 实际结果:{actual} || 预期结果: {_v}')
case_handle.py Case数据读取工具类
def get_case_data():
case_type = ReadYaml(config_path + "config.yaml").read_yaml["case"]
if case_type == CaseType.EXCEL.value:
cases = []
for file in [excel for excel in os.listdir(data_path) if os.path.splitext(excel)[1] == ".xlsx"]:
data = ReadExcel(data_path + file).read_excel()
name = os.path.splitext(file)[0]
class_name = name.split("_")[0].title() + name.split("_")[1].title()
gen_case(name, data, class_name)
cases.extend(data)
return cases
elif case_type == CaseType.YAML.value:
cases = []
for yaml_file in [yaml for yaml in os.listdir(data_path) if
os.path.splitext(yaml)[1] in [".yaml", "yml"]]:
data = ReadYaml(data_path + yaml_file).read_yaml
name = os.path.splitext(yaml_file)[0]
class_name = name.split("_")[0].title() + name.split("_")[1].title()
gen_case(name, data, class_name)
cases.extend(data)
return cases
else:
cases = []
for file in [excel for excel in os.listdir(data_path) if
os.path.splitext(excel)[1] in [".yaml", "yml", ".xlsx"]]:
if os.path.splitext(file)[1] == ".xlsx":
data = ReadExcel(data_path + file).read_excel()
name = os.path.splitext(file)[0]
cases.extend(data)
else:
data = ReadYaml(data_path + file).read_yaml
name = os.path.splitext(file)[0]
cases.extend(data)
class_name = name.split("_")[0].title() + name.split("_")[1].title()
gen_case(name, data, class_name)
return cases
excel_handle.py 读取Excel工具类
def get_case_data():
case_type = ReadYaml(config_path + "config.yaml").read_yaml["case"]
if case_type == CaseType.EXCEL.value:
cases = []
for file in [excel for excel in os.listdir(data_path) if os.path.splitext(excel)[1] == ".xlsx"]:
data = ReadExcel(data_path + file).read_excel()
name = os.path.splitext(file)[0]
class_name = name.split("_")[0].title() + name.split("_")[1].title()
gen_case(name, data, class_name)
cases.extend(data)
return cases
elif case_type == CaseType.YAML.value:
cases = []
for yaml_file in [yaml for yaml in os.listdir(data_path) if
os.path.splitext(yaml)[1] in [".yaml", "yml"]]:
data = ReadYaml(data_path + yaml_file).read_yaml
name = os.path.splitext(yaml_file)[0]
class_name = name.split("_")[0].title() + name.split("_")[1].title()
gen_case(name, data, class_name)
cases.extend(data)
return cases
else:
cases = []
for file in [excel for excel in os.listdir(data_path) if
os.path.splitext(excel)[1] in [".yaml", "yml", ".xlsx"]]:
if os.path.splitext(file)[1] == ".xlsx":
data = ReadExcel(data_path + file).read_excel()
name = os.path.splitext(file)[0]
cases.extend(data)
else:
data = ReadYaml(data_path + file).read_yaml
name = os.path.splitext(file)[0]
cases.extend(data)
class_name = name.split("_")[0].title() + name.split("_")[1].title()
gen_case(name, data, class_name)
return cases
yaml_handle.py 读取Yaml文件的工具类
class ReadYaml:
def __init__(self, filename):
self.filename = filename
@property
def read_yaml(self) -> object:
with open(file=self.filename, mode="r", encoding="utf-8") as fp:
case_data = yaml.safe_load(fp.read())
return case_data
config.yaml 配置信息
# 服务器器地址 host: http://localhost:8091/ case: 1 # 0代表执行Excel和yaml两种格式的用例, 1 代表Excel用例,2 代表 yaml文件用例
日志输出内容介绍
import logging
import time
import os
def get_log(logger_name):
"""
:param logger_name: 日志名称
:return: 返回logger handle
"""
# 创建一个logger
logger = logging.getLogger(logger_name)
logger.setLevel(logging.INFO)
# 获取本地时间,转换为设置的格式
rq = time.strftime('%Y%m%d', time.localtime(time.time()))
# 设置所有日志和错误日志的存放路径
path = os.path.dirname(os.path.abspath(__file__))
all_log_path = os.path.join(path, 'interface_logs\\All_Logs\\')
if not os.path.exists(all_log_path):
os.makedirs(all_log_path)
error_log_path = os.path.join(path, 'interface_logs\\Error_Logs\\')
if not os.path.exists(error_log_path):
os.makedirs(error_log_path)
# 设置日志文件名
all_log_name = all_log_path + rq + '.log'
error_log_name = error_log_path + rq + '.log'
if not logger.handlers:
# 创建一个handler写入所有日志
fh = logging.FileHandler(all_log_name, encoding='utf-8')
fh.setLevel(logging.INFO)
# 创建一个handler写入错误日志
eh = logging.FileHandler(error_log_name, encoding='utf-8')
eh.setLevel(logging.ERROR)
# 创建一个handler输出到控制台
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
# 以时间-日志器名称-日志级别-文件名-函数行号-错误内容
all_log_formatter = logging.Formatter(
'[%(asctime)s] %(filename)s - %(levelname)s - %(lineno)s - %(message)s')
# 以时间-日志器名称-日志级别-文件名-函数行号-错误内容
error_log_formatter = logging.Formatter(
'[%(asctime)s] %(filename)s - %(levelname)s - %(lineno)s - %(message)s')
# 将定义好的输出形式添加到handler
fh.setFormatter(all_log_formatter)
ch.setFormatter(all_log_formatter)
eh.setFormatter(error_log_formatter)
# 给logger添加handler
logger.addHandler(fh)
logger.addHandler(eh)
logger.addHandler(ch)
return logger
报告内容介绍
执行case后自动生成,执行之前自动删除
allure 数据内容介绍
执行case后自动生成,执行之前自动删除
base_request.py 请求封装工具类
class BaseRequest:
session = None
@classmethod
def get_session(cls):
if cls.session is None:
cls.session = requests.Session()
return cls.session
@classmethod
def send_request(cls, case: dict) -> Response:
"""
处理case数据,转换成可用数据发送请求
:param case: 读取出来的每一行用例内容
return: 响应对象
"""
log.info("开始执行用例: {}".format(case.get("title")))
req_data = RequestPreDataHandle(case).to_request_data
res = cls.send_api(
url=req_data["url"],
method=req_data["method"],
pk=req_data["pk"],
header=req_data.get("header", None),
data=req_data.get("data", None),
file=req_data.get("file", None)
)
allure_step('请求响应数据', res.text)
after_extract(res, req_data.get("extract", None))
return res
@classmethod
def send_api(cls, url, method, pk, header=None, data=None, file=None) -> Response:
"""
:param method: 请求方法
:param url: 请求url
:param pk: 入参关键字, params(查询参数类型,明文传输,一般在url" />

日志记录
[2022-01-11 22:36:04,164] base_request.py - INFO - 42 - 开始执行用例: 正常登录
[2022-01-11 22:36:04,165] pre_handle_utils.py - INFO - 37 - 开始进行字符串替换: 替换字符串为:bank/api/login
[2022-01-11 22:36:04,165] pre_handle_utils.py - INFO - 44 - 字符串替换完成: 替换字符串后为:bank/api/login
[2022-01-11 22:36:04,165] pre_handle_utils.py - INFO - 68 - 处理请求前url:bank/api/login
[2022-01-11 22:36:04,165] pre_handle_utils.py - INFO - 78 - 处理请求后 url:http://localhost:8091/bank/api/login
[2022-01-11 22:36:04,165] pre_handle_utils.py - INFO - 90 - 处理请求前Data: {'password': '123456', 'userName': 'king'}
[2022-01-11 22:36:04,165] pre_handle_utils.py - INFO - 37 - 开始进行字符串替换: 替换字符串为:{'password': '123456', 'userName': 'king'}
[2022-01-11 22:36:04,166] pre_handle_utils.py - INFO - 44 - 字符串替换完成: 替换字符串后为:{'password': '123456', 'userName': 'king'}
[2022-01-11 22:36:04,166] pre_handle_utils.py - INFO - 92 - 处理请求后Data: {'password': '123456', 'userName': 'king'}
[2022-01-11 22:36:04,166] pre_handle_utils.py - INFO - 100 - 处理请求前files: None
[2022-01-11 22:36:04,175] base_request.py - INFO - 53 - 请求响应数据{"code":"0","message":"success","data":null}
[2022-01-11 22:36:04,176] data_handle.py - INFO - 29 - 提取响应内容成功,提取表达式为: $.code 提取值为 0
[2022-01-11 22:36:04,176] assert_util.py - INFO - 49 - 第1个断言数据,实际结果:0 | 预期结果:0 断言方式:eq
[2022-01-11 22:36:04,176] data_handle.py - INFO - 29 - 提取响应内容成功,提取表达式为: $.message 提取值为 success
[2022-01-11 22:36:04,176] assert_util.py - INFO - 49 - 第2个断言数据,实际结果:success | 预期结果:success 断言方式:eq
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍了python如何判断网络是否通?具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
这篇文章主要介绍了python处理excel文件之xlsxwriter 模块,文章围绕主题展开详细的内容介绍,需要的小伙伴可以参考一下,希望对你的学习有所帮助
这篇文章主要为大家介绍了如何利用Python语言实现在Excel文件中写入一个比较简单的图表,文中的实现方法讲解详细,快动手尝试一下吧
一、super()的入门使用-在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现,比如:classAnimal(object):def__init__(self,name):self.name=namedefgre
python3 x拼接字符串一般有以下几种方法:1 直接通过(+)操作符拼接s=& 39;Hello& 39;+& 39;& 39;+& 39;World& 39;+& 39;!& 39;print(s)
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008