使用HttpRunner默认生成的项目是这样的

  命令:httprunner --startproject  项目名称

so,根据这个项目的目录结构,使用python解析swagger接口参数,可以快速生成api、testcases、testsuites文件夹中用到的json文件

运行后的目录是这样的

  api目录

    按swagger中的tags区分为多个文件夹,每个文件夹下包含各自的api文件

  

  testcases目录

    按swagger中的tags区分为不同的json文件,每个文件包含所有的api接口

  

  testsuites目录

    测试用例集,组织运行所有的测试用例

  

 这样,接口测试框架的简易架子就有了。接下来,需要补充api接口文件数据

 

 略

 

运行结果

  

 HttpRunner自带的report

  

附lib目录下的代码

  swagger.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/9/9 15:17
# @Author : lixiaofeng
# @Site :
# @File : swagger.py
# @Software: PyCharm import os, requests
from httprunner import logger
from lib.processingJson import write_data, get_json class AnalysisJson:
"""swagger自动生成测试用例""" def __init__(self, url):
self.url = url
self.interface = {}
self.case_list = []
self.tags_list = []
self.http_suite = {"config": {"name": "", "base_url": "", "variables": {}},
"testcases": []}
self.http_testcase = {"name": "", "testcase": "", "variables": {}} def retrieve_data(self):
"""
主函数
:return:
"""
try:
r = requests.get(self.url + '/v2/api-docs?group=sign-api').json()
write_data(r, 'data.json')
# r = get_json('D:\HttpRunner_framework\\testcases\data.json')
except Exception as e:
logger.log_error('请求swagger url 发生错误. 详情原因: {}'.format(e))
return 'error'
self.data = r['paths'] # 接口数据
self.url = 'https://' + r['host']
self.title = r['info']['title']
self.http_suite['config']['name'] = self.title
self.http_suite['config']['base_url'] = self.url self.definitions = r['definitions'] # body参数
for tag_dict in r['tags']:
self.tags_list.append(tag_dict['name'])
i = 0
for tag in self.tags_list:
self.http_suite['testcases'].append({"name": "", "testcase": "", "variables": {}})
self.http_suite['testcases'][i]['name'] = tag
self.http_suite['testcases'][i]['testcase'] = 'testcases/' + tag + '.json'
i += 1 suite_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname("__file__"), os.path.pardir)),
'testsuites')
testcase_path = os.path.join(suite_path, 'demo_testsuite.json')
write_data(self.http_suite, testcase_path)
if isinstance(self.data, dict):
for tag in self.tags_list:
self.http_case = {"config": {"name": "", "base_url": "", "variables": {}}, "teststeps": []} for key, value in self.data.items():
for method in list(value.keys()):
params = value[method]
if not params['deprecated']: # 接口是否被弃用
if params['tags'][0] == tag:
self.http_case['config']['name'] = params['tags'][0]
self.http_case['config']['base_url'] = self.url
case = self.retrieve_params(params, key, method, tag)
self.http_case['teststeps'].append(case)
else:
logger.log_info(
'interface path: {}, if name: {}, is deprecated.'.format(key, params['description']))
break
api_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname("__file__"), os.path.pardir)),
'testcases')
testcase_path = os.path.join(api_path, tag + '.json')
write_data(self.http_case, testcase_path) else:
logger.log_error('解析接口数据异常!url 返回值 paths 中不是字典.')
return 'error' def retrieve_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_testcase = {"name": "", "api": "", "variables": {}, "validate": [], "extract": [], "output": []} name = params['summary'].replace('/', '_')
http_interface['name'] = name
http_testcase['name'] = name
http_testcase['api'] = 'api/{}/{}.json'.format(tag, name)
http_interface['request']['method'] = method.upper()
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:
param_key = ref.split('/')[-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 'example' in key:
http_interface['request']['params'].update({name: each[key]})
for each in parameters:
# if each.get('in') == 'path':
# name = each.get('name')
# for key in each.keys():
# if 'example' in key:
# http_interface['request']['json'].update({name: each[key]})
# else:
#
# http_interface['request']['json'].update({name: ''})
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_testcase['validate'].append({"eq": []})
http_testcase['validate'][i]['eq'].append('content.' + k)
http_testcase['validate'][i]['eq'].append(v['example'])
i += 1
else:
http_interface['validate'].append({"eq": []})
else:
http_interface['validate'].append({"eq": []})
if http_interface['request']['json'] == {}:
del http_interface['request']['json']
if http_interface['request']['params'] == {}:
del http_interface['request']['params'] api_path = os.path.join(os.path.abspath(os.path.join(os.path.dirname("__file__"), os.path.pardir)), 'api')
tags_path = os.path.join(api_path, tag)
if not os.path.exists(tags_path):
os.mkdir(tags_path)
json_path = os.path.join(tags_path, http_interface['name'] + '.json')
write_data(http_interface, json_path) return http_testcase if __name__ == '__main__':
AnalysisJson('').retrieve_data()

简单的实现了功能,代码有些粗糙~~~

  processingJson.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/9/9 15:18
# @Author : lixiaofeng
# @Site :
# @File : processingJson.py
# @Software: PyCharm import json
from httprunner import logger def get_json(path, field=''):
"""
获取json文件中的值,data.json和res.json可共用
:param path:
:param field:
:return:
"""
with open(path, 'r', encoding='utf-8') as f:
json_data = json.load(f)
if field:
data = json_data.get(field)
return data
else:
return json_data def write_data(res, json_path):
"""
把处理后的参数写入json文件
:param res:
:param json_path:
:return:
"""
if isinstance(res, dict) or isinstance(res, list):
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(res, f, ensure_ascii=False, sort_keys=True, indent=4)
logger.log_info('Interface Params Total:{} ,write to json file successfully!\n'.format(len(res)))
else:
logger.log_error('{} Params is not dict.\n'.format(write_data.__name__))

具体业务场景的测试,可以按照导入.har文件的方法快速生成,总之还是挺便捷的。

之前就有关注HttpRunner,终于有空花了一天时间,大致过了一遍中文文档,简单的记录下学习成果~~~

关键字:parameters 参数化

层级很重要 testcase

{
"config": {
"name": "添加发布会测试用例",
"variables": {}
},
"testcases": [
{
"name": "添加发布会",
"testcase": "testsuites/test.json",
"parameters": {
"limit": [
"",
""
]
}
}
]
}

teststeps

{
"config": {
"base_url": "http://www.easytest.xyz/api",
"name": "添加发布会",
"variables": {
"name": "${get_random_name()}",
"address": "${get_random_address()}",
"eid": "${get_random_num()}",
"limit": "${get_random_num_list()}"
},
"output": [
"limit"
]
},
"teststeps": [
{
"name": "添加发布会",
"request": {
"headers": {},
"data": {
"eid": "$eid",
"name": "$name",
"limit": "$limit",
"address": "$address",
"start_time": "2019-11-30",
"status": ""
},
"method": "POST",
"url": "/add_event/"
},
"validate": [
{
"eq": [
"content.message",
"add event success"
]
}
]
}
]
}

运行

from httprunner.api import HttpRunner
runner = HttpRunner(failfast=True)
runner.run(r'D:\HttpRunner_framework\testsuites\testcase_test.json')
print(runner.summary)

结果

基于HttpRunner,解析swagger数据,快速生成接口测试框架的更多相关文章

  1. 使用excel中的数据快速生成sql语句

    在小公司的话,总是会有要开发去导入历史数据(数据从旧系统迁移到新系统上)的时候.这个时候,现场实施或客户会给你一份EXCEL文档,里面包含了一些别的系统上的历史数据,然后就让你导入到现在的系统上面去. ...

  2. 代码生成工具更新--快速生成Winform框架的界面项目

    在之前版本的代码生成工具Database2Sharp中,由于代码生成都是考虑Winform和Web通用的目的,因此Winform界面或者Web界面都是单独生成的,在工具中生成相应的界面后,复制到项目里 ...

  3. 【Java POI】POI基于事件驱动解析大数据量2007版本Excel,空值导致列错位问题

    1.目前测试了20M的文件,可以读取. 2.支持单个工作表1万+的数据行数,耗时如图. 3.以下是关键地方处理的代码 //Accepts objects needed while parsing. / ...

  4. 基于SpringBoot的Web API快速开发基础框架

    其实还是很因为懒,才会有这个案例项目的产生,每次开启一个终端的小服务都要整理一次框架,造成重复的.不必要的.缺乏创造性的劳动,SO,本着可以用.用着简单的原则上传代码到Github,希望有需要的朋友直 ...

  5. 基于SpringBoot-Dubbo的微服务快速开发框架

    简介: 基于Dubbo的分布式/微服务基础框架,为前端提供脚手架开发服务,结合前一篇--Web AP快速开发基础框架,可快速上手基于Dubbo的分布式服务开发,项目代码: https://github ...

  6. 基于Swagger+SpringBoot快速构建javaweb项目

    章节导航 SpringBoot&Swagger简介 数据模型和接口定义 项目框架生成 业务逻辑实现 项目源码地址 github项目路径:https://github.com/Vikezhu/s ...

  7. 使用代码生成工具快速生成基于ABP框架的Vue+Element的前端界面

    世界上唯一不变的东西就是变化,我们通过总结变化的规律,以规律来应付变化,一切事情处理起来事半功倍.我们在开发后端服务代码,前端界面代码的时候,界面都是依照一定的规律进行变化的,我们通过抽取数据库信息, ...

  8. iOS开发之JSON格式数据的生成与解析

    本文将从四个方面对IOS开发中JSON格式数据的生成与解析进行讲解: 一.JSON是什么? 二.我们为什么要用JSON格式的数据? 三.如何生成JSON格式的数据? 四.如何解析JSON格式的数据? ...

  9. 转载 -- iOS开发之JSON格式数据的生成与解析

    本文将从四个方面对IOS开发中JSON格式数据的生成与解析进行讲解: 一.JSON是什么? 二.我们为什么要用JSON格式的数据? 三.如何生成JSON格式的数据? 四.如何解析JSON格式的数据? ...

随机推荐

  1. ztree复选框

    var setting = { check: { enable: true // chkboxType : { "Y" : "", "N" ...

  2. assertion的用法

    一.assertion的语法和语义     在软件开发中,assertion是一种经典的调试.测试方式,本文将深入解析assertion功能的使用以及其设计理念,并给出相关的例子. 清软国际java学 ...

  3. 191022Django模板

    一.变量和句点符深度查找 字符串变量引用 def show_time(request): now_time = datetime.datetime.now() return render(reques ...

  4. ftp反向代理配置

    说明:源ftp在内网,访问在另一个内网,要求用户对真实ftp地址透明,且免密访问. 1.将ftp配置为被动模式,指定被动访问端口映射出来. // vsftp配置被动模式,列出主要配置 connect_ ...

  5. 深入理解android的UI更新机制

    深入理解android的UI更新机制 由问题开始: 如何更新android UI? 可以通过如下方法: 在主线程里直接操作UI控件. handler.post(Runnable) runOnUiThr ...

  6. Kotlin之环境的配置和搭建

    第一步 . 安装和配置JDK http://www.cnblogs.com/loaderman/p/6402948.html 第二步 安装和下载Kotlin 进入Kotlin官网 :https :// ...

  7. flask url_for后没有带端口号

    问题描述: 在本地运行flask项目,当运行到下面这句代码时,正常重定向 return redirect(url_for('.script_case')) 但项目布署到服务器之后,代码运行一这句话,却 ...

  8. 使用zipkin2在SpringCloud2.0环境下追踪服务调用情况

    1.目的: 使用zipkin2.0在Spring Cloud 2.0环境下,追踪服务调用情况. 2.所需组件: zipkin2.0,Spring Cloud 2.0,Eureka Server,Eur ...

  9. java:LeakFilling(Spring)

    1.配置文件总结: bean节点: id:用户自定义名称,用于标识当前对象,可以通过getBean(String id)从容器中获取该对象. class:要交给spring容器创建的对象的全类名(包名 ...

  10. AWSome Day简介

    AWSome Day是什么? 它是一场为时一天.结合教育与技术新知的云计算技术免费研讨会.是面向所有开发人员.IT技术人员.或技术/业务领域决策者必备的基础云计算课程.AWS专业级讲师将在现场带领您从 ...