本文正在参加「Python主题月」,详情查看 活动链接
一、HTTPRUNNER开源项目
当前框架已经更新到3.x版本;已经向pytest测试框架靠拢,并继承它的相关特性及优点。
复制代码
- 但它的优点,在某些人眼里也是有‘缺陷’的
如:它支持抓包导出har数据文件har2case转化成json/yaml格式的测试套件;也支持手动编辑维护json/yaml格式的测试用例;
但是面对接口文档,比较多的接口需要做接口测试或集成方面又略显不足,人力的手工成本大、效率又不高,有没有办法提高呢?
故而开发与该框架契合比较高的解析接口文档工具,既支持json/yaml格式又可以输出excel文档,方便更灵活的开发测试框架。
复制代码
- 咱们先安装环境,然后再一步一步完成自己的需求
// 暂时不使用它3.x版本的功能
pip install -y httprunner==2.1.3
复制代码
- 验证环境:hrun -h ,等效于httprunner -h
二、开发解析swagger脚本
- 先安装环境所需要的python库
// 可以写入requirements.txt文件,批量安装:pip install -r requirements.txt
openpyxl==3.0.4
requests==2.24.0
xlwt==1.3.0
xlrd==1.2.0
PyYAML==5.4.1
复制代码
- 开发工具及工程结构
-
- pycharm是python工程师的开发利器
-
- 工程结构截图如下:
- 请注意配置properties/目录下的config.ini配置文件,需要填写自己解析的接口文档地址
[swaggerUrl]
# swagger接口文档地址
baseSever_url = http://localhost:8090
复制代码
例:自己部署一个swagger项目演示效果
- 效果如下:
- 但是我们要的不是UI,而是接口,于是F12一开
-
- 拿到接口地址并写入config.ini配置文件:http://localhost:8090/v2/api-docs
三、跳过开发过程看效果演示
脚本设计思想:
1、既要符合httprunner框架支持的json/yaml用例,又要支持excel输出
2、这点思想主要来源于爬虫,爬取接口响应的数据进行解析重新组装输出
复制代码
脚本核心代码,更多请上github查看
- 清洗数据函数
def wash_params(self, params, api, method, tag):
"""
清洗数据json,把每个接口数据都加入到一个字典中
:param params:
:param params_key:
:param method:
:param key:
:return:
replace('false', 'False').replace('true', 'True').replace('null','None')
"""
# 定义接口数据格式
http_interface = {"name": "", "variables": {},
"request": {"url": "", "method": "", "headers": {}, "json": {}, "params": {}}, "validate": [],
"output": []}
# 测试用例的数据格式:
http_api_testcase = {"name": "", "api": "", "variables": {
}, "validate": [], "extract": [], "output": []}
# 这里的问题需要具体来分析,开发有时概要使用其他符号分割///分割符号需要替换
case_name = params['summary']#.replace('/', '_').replace(" ", "_").replace(":", "_")
case_name=re_pattern(case_name)
# 用例名称
http_interface['name'] = case_name
http_api_testcase['name'] = case_name
# 这是写入testcasejson下的名字,不是生成api的目录
http_api_testcase['api'] = 'api/{}/{}.json'.format(tag, case_name)
# 所有方法大写
http_interface['request']['method'] = method.upper()
# 这个是替换uri中的/get请求的拼接方式,有些是?参数=&参数拼接,需要另外解析
http_interface['request']['url'] = api.replace(
'{', '$').replace('}', '')
parameters = params.get('parameters') # 未解析的请求参数
responses = params.get('responses') # 未解析的响应参数
if not parameters: # 确保参数字典存在
parameters = {}
# 给测试用例字典,加入解析出来的参数
for each in parameters:
if each.get('in') == 'body': # body 和 query 不会同时出现
schema = each.get('schema')
if schema:
ref = schema.get('$ref')
if ref:
# 这个uri拆分,根据实际情况来取第几个/反斜杠
param_key = ref.split('/', 2)[-1]
param = self.definitions[param_key]['properties']
for key, value in param.items():
if 'example' in value.keys():
http_interface['request']['json'].update(
{key: value['example']})
else:
http_interface['request'][
'json'].update({key: ''})
# 实际是请求方法或者是请求参数的格式
elif each.get('in') == 'query':
name = each.get('name')
for key in each.keys():
if not 'example' in key: # 取反,要把在query的参数写入json测试用例
http_interface['request'][
'params'].update({name: each[key]})
# 解析接口文档请求参数
for each in parameters:
if each.get('in') == 'header':
name = each.get('name')
for key in each.keys():
if 'example' in key:
http_interface['request'][
'headers'].update({name: each[key]})
else:
if name == 'token':
http_interface['request'][
'headers'].update({name: '$token'})
else:
http_interface['request'][
'headers'].update({name: ''})
# 解析接口文档响应参数
for key, value in responses.items():
schema = value.get('schema')
if schema:
ref = schema.get('$ref')
if ref:
param_key = ref.split('/')[-1]
res = self.definitions[param_key]['properties']
i = 0
for k, v in res.items():
if 'example' in v.keys():
http_interface['validate'].append({"eq": []})
http_interface['validate'][i][
'eq'].append('content.' + k)
http_interface['validate'][i][
'eq'].append(v['example'])
http_api_testcase['validate'].append({"eq": []})
http_api_testcase['validate'][i][
'eq'].append('content.' + k)
http_api_testcase['validate'][
i]['eq'].append(v['example'])
i += 1
else:
if len(http_interface['validate']) != 1:
http_interface['validate'].append({"eq": []})
else:
if len(http_interface['validate']) != 1:
http_interface['validate'].append({"eq": []})
# 判断如果断言为空,则默认添加http状态断言
if http_interface.get("validate"):
http_interface.get("validate")[0].update({"eq":["status_code", 200]})
# 测试用例的请求参数为空字典,则删除这些key
if http_interface['request']['json'] == {}:
del http_interface['request']['json']
if http_interface['request']['params'] == {}:
del http_interface['request']['params']
# 定义接口测试用例
tags_path = os.path.join(case_dir, tag).replace("/", "_").replace(" ", "_")
# 创建不存在的文件目录,递归创建
if not os.path.exists(tags_path):
os.makedirs(tags_path)
# 拼接api用例路径
json_path = os.path.join(tags_path, case_name + '.json')
# testcases/写入数据
write_data(http_interface, json_path)
return http_api_testcase
复制代码
- 进入脚本,执行程序入口
if __name__ == '__main__':
url = conf.get_value("swaggerUrl", "baseSever_url")
js = AnalysisSwaggerJson(url)
js.analysis_json_data(isDuplicated=False)
js.write_excel(url, handlefile.get_file_list(case_dir))
复制代码
- 结果输出如图所示
- 既有json,同时又有excel文件,是不是两全其美之法?
先来完善api/目录下的测试用例:
- 补全接口入参,如图所示
- 进入工程swagger用例目录,执行:hrun testcases\用户相关接口.json,日志截图:
- 并且生成html测试报告,打开如图:
- 是不是非常nice
一边生成json/yaml符合httprunner测试框架;
一边生成excel可以自己定制开发自动化测试框架。
复制代码
四、Swagger工具总结
- 先推广一波httprunner_swagger小工具,已经有19个star了,还缺你哦;
- 欢迎提出不同优化建议,如果再结合其他测试框架,做成一个强大第三方开源库,服务更多的人群,这该是一件美事!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END