感谢大家关注,帮忙分享呦,你们的阅读就是我的动力!!!
公众号:小李测试随笔


第八章 设计zrlog项目接口自动化测试框架(8.5章节)
8.5 zrlog接口测试框架核心层级设计

8.5.1 建立common核心层并封装base.py文件

common核心层主要用作存放接口框架中所需要的公共方法,这些公共方法将通过base.py文件进行封装,并供框架中其他类使用。建立common层并封装base.py文件的步骤可以分为三步
第一步,在zrlog接口自动化项目下新建common包名

第二步,在common包下新建base.py文件

第三步,在base.py文件编写公共方法
# coding=utf-8
# 导入json库
import json
# 导入Template类
from string import Template
# 导入re库
import re
# 根据参数匹配内容
def find(data):
# 判断data类型是否为字典
if isinstance(data, dict):
# 对象格式化为str
data = json.dumps(data)
# 定义正则匹配规则
pattern = "\\${(.*?)}"
# 按匹配进行查询,把查询的结果返回
return re.findall(pattern, data)
# 进行参数替换
def relace(ori_data, replace_data):
# 对象格式化为str
ori_data = json.dumps(ori_data)
# 处理字符串的类,实例化并初始化原始字符
s = Template(ori_data)
# 使用新的字符,替换
return s.safe_substitute(replace_data)
# 根据var,逐层获取json格式的值
def parse_relation(var,resdata):
# 判断变量var是否存在
if not var:
# 不存在直接返回resdata内容
return resdata
else:
# 存在则获取数组第1个内容
resdata = resdata.get(var[0])
# 从数组中删除第1个内容
del var[0]
# 递归
return parse_relation(var,resdata)
# 测试代码
if __name__ == '__main__':
ori_data = {"admin-token": "${token}"}
replace_data = {'token': 'x015k878'}
print(relace(ori_data, replace_data))
red = find({"id":"${id_name}","editorType":"markdown","title":"付出才能杰出","alias":"${alias_name}","thumbnail":None,"typeId":"1","keywords":None,"digest":"付出
","canComment":False,"recommended":False,"privacy":False,"content":"付出
\n","markdown":"付出","rubbish":False})
print(red)
8.5.2 建立testcase核心层并封装test_run.py文件

testcase层是整个接口框架中最重要的层级,用来存放接口框架中的主程序文件test_run.py文件。test_run.py文件提供用例执行的入口,用例执行,结果验证等功能。建立testcase层并封装test_run.py文件的步骤可分为三步。
第一步,在zrlog接口自动化项目下新建testcase包名

第二步,新建test_run文件

第三步,编写接口框架主程序脚本
# coding=utf-8
# 导入datetime库
import datetime
# 导入DynamicParam类
from config.settings import DynamicParam
# 导入logger对象
from utils.logutil import logger
# 导入base()方法
import common.base as Base
# 导入json库
import json
# 导入pytest框架
import pytest
# RdTestcase类
from utils.readmysql import RdTestcase
# 导入RequestSend类
from utils.requestsutil import RequestSend
# 初始化类
attribute = DynamicParam()
# 实例化测试用例对象
case_data = RdTestcase()
# 根据测试用例对象获取测试用例列表
case_list = case_data.is_run_data('zrlog')
# 获取当前时间
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# 测试用例执行类
class TestApi:
# 类方法,运行开始前只执行1次
def setup_class(self):
# 打印日志
logger.info(f"***** 开始执行测试用例,开始时间为:{current_time} *****")
# 类方法,运行结束后只执行1次
def teardown_class(self):
# 打印日志
logger.info(f"***** 执行用例完成,完成时间为:{current_time} *****")
# 测试用例参数化
@pytest.mark.parametrize('case', case_list)
def test_run(self, case):
# 定义变量
res_data = None
# 根据条件,从数据库获取url信息,并拼接完整url信息
url = case_data.loadConfkey('zrlog', 'url_api')['value'] + case['url']
# 获取method内容
method = case['method']
# 获取headers内容,格式化字符为字典
headers = eval(case['headers'])
# 获取cookies内容,格式化字符为字典
cookies = eval(case['cookies'])
# 获取请求内容,格式化字符为字典
data = eval(case['request_body'])
# 获取关联内容
relation = str(case['relation'])
# 获取测试用例名称
case_name = case['title']
# 根据关联,获取headers参数中是否有变量需要被替换,有则替换,无则默认
headers = self.correlation(headers)
# 根据关联,获取cookies参数中是否有变量需要被替换,有则替换,无则默认
cookies = self.correlation(cookies)
# 根据关联,获取data参数中是否有变量需要被替换,有则替换,无则默认
data = self.correlation(data)
# 异常处理
try:
# 打印日志
logger.info("正在执行{}用例".format(case_name))
# 执行测试用例,发送http请求
res_data = RequestSend().send(url, method, data=data, headers=headers, cookies=cookies)
# 打印日志
logger.info("用例执行成功,请求的结果为{}".format(res_data))
# 异常捕获
except:
# 打印日志
logger.info("用例执行失败,请查看日志找原因。")
# 断言结果为失败
assert False
# 判断res_data是否存在
if res_data:
# res_data存在后,判断relation不为None
if relation != "None":
# 根据响应结果,以及关联信息(token=cookies.admin-token),设置变量token的值为响应结果的信息
self.set_relation(relation, res_data)
# 结果进行验证
self.assert_respoes(case, res_data)
# 返回res_data信息
return res_data
# 响应结果关联设置函数
def set_relation(self, relation, res_data):
# 异常处理
try:
# 判断relation内容为True
if relation:
# 根据,进行分割,结果为List
relation = relation.split(",")
# 循环打印relation列表
for i in relation:
# 根据=进行分割
var = i.split("=")
# 列表第1个值设置为var_name
var_name = var[0]
# 列表第2值内容按.进行分割,结果内容保存变量var_tmp
var_tmp = var[1].split(".")
# 在响应结果res_data中,根据条件var_tmp进行匹配
res = Base.parse_relation(var_tmp, res_data)
# 打印信息
print(f"{var_name}={res}")
# 把定义的变量名称以及值 以属性的方式设置到DynamicParam类中,实现动态存储
setattr(DynamicParam, var_name, res)
# 捕获异常
except Exception as e:
# 打印异常信息
print(e)
# 根据关联,获取该变量内容
def correlation(self, data):
# 根据正则,获取数据
res_data = Base.find(data)
# 判断res_data为True
if res_data:
# 定义空的字典
replace_dict = {}
# 循环打印
for i in res_data:
# 根据名称,从DynamicParam动态获取属性值,并把结果内容赋值给变量data_tmp
data_tmp = getattr(DynamicParam, str(i), "None")
# 把结果更新到字典replace_dict中
replace_dict.update({str(i): data_tmp})
# 参数进行替换,并把str转换为python对象
data = json.loads(Base.relace(data, replace_dict))
# 返回结果
return data
# 结果验证方法
def assert_respoes(self, case, res_data):
# 变量初始化为False
is_pass = False
# 异常处理,捕获assert抛出的异常,不直接抛出
try:
# 根据结果进行断言验证
assert int(res_data['body']['error']) == int(case['expected_code'])
# 打印信息
logger.info("用例断言成功")
# 设置变量为True
is_pass = True
# 捕获异常
except:
# 设置变量为False
is_pass = False
# 打印日志
logger.info("用例断言失败")
# 无论是否出现异常,都执行下面内容代码
finally:
# 把结果更新到数据库
case_data.updateResults(res_data, is_pass, str(case['id']))
# 根据变量结果是True/False,进行断言验证,成功则通过,失败则未通过
assert is_pass
# 返回该变量结果
return is_pass
# 主程序执行入口
if __name__ == '__main__':
pytest.main(['-s', '-v', 'test_run.py'])
8.5.3 通过pytest框架运行test_run.py文件


8.5.4 通过log层查看运行日志


8.5.5 通过report层查看测试报告

report层负责存储测试报告,脚本运行完成后,将会在该层下自动生成HTML格式的测试报告。

可以看到,11个测试用例都全部通过


END
