使用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. java实现数据库之间批量插入数据

    package comnf147Package; import java.sql.*; public class DateMigrationLagou { //连接SQLite private Con ...

  2. AOI 设计

    http://blog.csdn.net/zhanghefu/article/details/25833535 云风的Blog 并进行整理而写. AOI(Area Of Interest),中文就是感 ...

  3. leetcode-easy-string-387 First Unique Character in a String

    mycode  24.42% class Solution: def firstUniqChar(self, s: str) -> int: dic = {} for i in range(le ...

  4. LeetCode 5——最长回文子串

    1. 题目 2. 解答 我们定义状态 state[i][j] 表示子串 s[i, j] 是否为回文子串,如果 s[i, j] 为回文子串,并且有 s[i-1] == s[j+1],那么 s[i-1, ...

  5. 浏览器端-W3School-HTML:HTML DOM Select 对象

    ylbtech-浏览器端-W3School-HTML:HTML DOM Select 对象 1.返回顶部 1. HTML DOM Select 对象 Select 对象 Select 对象代表 HTM ...

  6. flutter runtimeType

    通过runtimeType可以获取当前数据类型 var a = 10; var b = 10.0; var c = '10'; var d = true; var e = [12.5,13.1]; v ...

  7. 阶段3 2.Spring_06.Spring的新注解_4 spring的新注解-Import

    把Configuration的直接先注释掉 那么运行测试类的查询所有 并不影响我们的使用 不写同样可以执行的原因是因为这里把SpringConfiguration这个类作为方法传入进去了 新建 Spr ...

  8. 三十三:数据库之SQLAlchemy.filter常用的过滤条件

    准备数据 等于 不等于 like(区分大小写,模糊查询).ilike(不区分大小写) in not in(~,取反) 字段为空 不为空 and or

  9. javascript-->getElementsByClass

        //通过类名获取元素    //obj->目标元素的上一层元素  cName->目标类名 tagName->目标的标签类型(可缺省)    function getEleme ...

  10. linu基础命令1

    /根目录,第一级目录 1.ls列出当前目录下的文件和目录-a: 列出所有的文件,包括所有以.开头的隐藏文件-d: 列出目录本身,并不包含目录中的文件(-ld)-h: 和-l一起使用,文件大小人类易读 ...