当前位置: 首页 > news >正文

Yapi接口文档导出测试用例至Excel中

前言

因为项目要求测试用例必须是excel,而且Yapi导出选项中没有excel,所以写个脚本方便以后一键生成。

实现

利用python实现

import jsonimport pandas as pd
import requestsclass YapiToExcel:def __init__(self, yapi_url, token, cookies, project_name, use_test_case):self.yapi_url = yapi_url.rstrip('/')self.token = tokenself.headers = {'Content-Type': 'application/json','Authorization': f'{token}'}self.cookies = cookiesself.project_name = project_nameself.use_test_case = use_test_casedef _generate_request_body_example(self, schema):"""根据JSON Schema生成请求体示例"""if not isinstance(schema, dict) or schema.get('type') != 'object':return json.dumps(schema, ensure_ascii=False, indent=2)properties = schema.get('properties', {})required = schema.get('required', [])# 构建示例请求体example_body = {}for prop_name, prop_info in properties.items():if not isinstance(prop_info, dict):continue# 获取属性类型prop_type = prop_info.get('type', 'string')# 优先使用mock值mock_info = prop_info.get('mock', {})if mock_info and 'mock' in mock_info:example_body[prop_name] = mock_info['mock']else:# 根据类型填充默认值if prop_type == 'string':example_body[prop_name] = ""elif prop_type == 'integer':example_body[prop_name] = 0elif prop_type == 'number':example_body[prop_name] = 0elif prop_type == 'boolean':example_body[prop_name] = Falseelif prop_type == 'array':example_body[prop_name] = []elif prop_type == 'object':example_body[prop_name] = {}else:example_body[prop_name] = ""return json.dumps(example_body, ensure_ascii=False, indent=2)def get_project_list(self):"""获取项目列表"""url = f"{self.yapi_url}/api/project/list"params = {'page': 1,'limit': 100,'token': self.token}response = requests.get(url, headers=self.headers, params=params)result = response.json()if result and result.get('errcode') == 0:return result.get('data', {})return {}def get_interface_list(self, project_id):"""获取项目下的接口列表"""url = f"{self.yapi_url}/api/interface/list"all_interfaces = []page = 1limit = 30  # 每页获取10条数据while True:params = {'project_id': project_id,'token': self.token,'page': page,'limit': limit}response = requests.get(url, params=params)result = response.json()if result and result.get('errcode') == 0:data = result.get('data', {})interfaces = data.get('list', [])all_interfaces.extend(interfaces)# 获取总数和当前数据数量total_count = data.get('count', 0)current_count = len(all_interfaces)# 如果已获取的数据量大于等于总数,或者当前页没有数据,则停止循环if not interfaces or current_count >= total_count:breakpage += 1else:breakreturn all_interfacesdef get_interface_detail(self, interface_id):"""获取接口详情"""url = f"{self.yapi_url}/api/interface/get"params = {'id': interface_id,'token': self.token}response = requests.get(url, params=params)result = response.json()if result and result.get('errcode') == 0:return result.get('data', {})return {}def get_test_case_list(self, project_id):"""获取项目下的测试用例集合列表"""url = f"{self.yapi_url}/api/col/list"params = {'project_id': project_id,# 'token': self.token}response = requests.get(url, params=params, cookies=self.cookies)result = response.json()if result and result.get('errcode') == 0:return result.get('data', [])return []def get_test_case_detail(self, test_case_id):"""获取测试用例详情"""url = f"{self.yapi_url}/api/col/case"params = {'caseid': test_case_id,'token': self.token}response = requests.get(url, params=params, cookies=self.cookies)result = response.json()if result and result.get('errcode') == 0:return result.get('data', {})return {}def extract_interface_case_data(self, interface_detail):"""提取测试用例数据"""if not interface_detail:return Noneparsed_body = None  # 或者根据业务逻辑设置合适的默认值# 请求路径path = interface_detail.get('path', '')# 请求方法method = interface_detail.get('method', '')# 请求头req_headers = interface_detail.get('req_headers', [])headers_str = json.dumps(req_headers, ensure_ascii=False) if req_headers else ''# 请求参数req_params = interface_detail.get('req_params', [])req_query = interface_detail.get('req_query', [])req_body = interface_detail.get('req_body_other', '') or interface_detail.get('req_body_form', '')req_body_example = ""  # 用于存储生成的请求体示例# if req_body:#     try:#         # 如果req_body是字符串形式的JSON,解析并格式化#         if isinstance(req_body, str):#             parsed_body = json.loads(req_body)#             req_body = json.dumps(parsed_body, ensure_ascii=False, indent=2)#         # 如果req_body已经是dict格式,直接格式化#         elif isinstance(req_body, dict):#             req_body = json.dumps(req_body, ensure_ascii=False, indent=2)#     except json.JSONDecodeError:#         # 如果解析失败,保持原始数据#         passif req_body:try:# 如果req_body是字符串形式的JSON,解析if isinstance(req_body, str):parsed_body = json.loads(req_body)# 如果req_body已经是dict格式elif isinstance(req_body, dict):parsed_body = req_body# 判断是否为JSON Schema格式if isinstance(parsed_body, dict) and 'type' in parsed_body and 'properties' in parsed_body:# 生成真实的请求体示例req_body_example = self._generate_request_body_example(parsed_body)# 保留原始Schema作为备用req_body = json.dumps(parsed_body, ensure_ascii=False, indent=2)else:# 普通JSON数据,格式化显示req_body_example = json.dumps(parsed_body, ensure_ascii=False, indent=2)req_body = req_body_exampleexcept json.JSONDecodeError:# 如果解析失败,保持原始数据pass# 如果没有生成示例请求体,则使用处理后的req_bodyif not req_body_example:req_body_example = req_body# 合并所有请求参数params_info = {'req_params': req_params,'req_query': req_query,'req_body': req_body}params_str = json.dumps(params_info, ensure_ascii=False)# 返回结果res_body = interface_detail.get('res_body', '')return {'项目名称': self.project_name,'测试用例ID': interface_detail.get('_id', ''),'测试用例名称': interface_detail.get('title', ''),'测试用例描述': '','请求路径': path,'请求方法': method,# 'Header头': headers_str,'请求query': req_query,'请求param': req_params,'请求body': req_body_example,'预期结果': res_body,'创建时间': interface_detail.get('add_time', ''),'更新时间': interface_detail.get('up_time', '')}def extract_test_collection_data(self, test_case_detail, project_name=""):"""提取测试集合数据"""if not test_case_detail:return None# 提取测试用例基本信息case_name = test_case_detail.get('casename', '')case_desc = test_case_detail.get('desc', '')path = test_case_detail.get('path', '')method = test_case_detail.get('method', '')# 请求头headers = test_case_detail.get('req_headers', [])headers_str = json.dumps(headers, ensure_ascii=False) if headers else ''# 请求头headers = test_case_detail.get('req_headers', [])headers_str = json.dumps(headers, ensure_ascii=False, indent=2) if headers else ''# 请求参数params = test_case_detail.get('req_query', [])params_str = json.dumps(params, ensure_ascii=False, indent=2) if params else ''req_query = test_case_detail.get('req_query', [])# 请求体数据req_body = test_case_detail.get('req_body_other', '')if req_body:try:# 如果req_body是字符串形式的JSON,解析并格式化if isinstance(req_body, str):parsed_body = json.loads(req_body)req_body = json.dumps(parsed_body, ensure_ascii=False, indent=2)# 如果req_body已经是dict格式,直接格式化elif isinstance(req_body, dict):req_body = json.dumps(req_body, ensure_ascii=False, indent=2)except json.JSONDecodeError:# 如果解析失败,保持原始数据pass# 预期响应res_body = test_case_detail.get('res_body', '')return {'项目名称': self.project_name,'测试用例ID': test_case_detail.get('_id', ''),'测试用例名称': case_name,'测试用例描述': case_desc,'请求路径': path,'请求方法': method,# 'Header头': headers_str,'请求query': req_query,'请求param': params_str,'请求body': req_body,'预期结果': res_body,'创建时间': test_case_detail.get('add_time', ''),'更新时间': test_case_detail.get('up_time', ''),}def export_project_to_excel(self, project_id, output_file):"""导出项目接口到Excel"""if self.use_test_case:all_test_cases = []test_cases_list = self.get_test_case_list(project_id)if test_cases_list:for test_cases in test_cases_list:for test_case in test_cases.get('caseList'):test_case_id = test_case.get('_id')if test_case_id:# 获取测试用例详情detail = self.get_test_case_detail(test_case_id)test_collection_data = self.extract_test_collection_data(detail, self.project_name)if test_collection_data:all_test_cases.append(test_collection_data)# 创建DataFrame并导出到Excelif all_test_cases:df = pd.DataFrame(all_test_cases)df.to_excel(output_file, index=False)print(f"成功导出 {len(all_test_cases)} 个接口到 {output_file}")else:print("没有找到有效的接口数据")else:# 获取接口列表interfaces = self.get_interface_list(project_id)if not interfaces:print("获取接口列表失败")returntest_cases = []for interface in interfaces:interface_id = interface.get('_id')if interface_id:# 获取接口详情detail = self.get_interface_detail(interface_id)test_case_data = self.extract_interface_case_data(detail)if test_case_data:test_cases.append(test_case_data)# 创建DataFrame并导出到Excelif test_cases:df = pd.DataFrame(test_cases)df.to_excel(output_file, index=False)print(f"成功导出 {len(test_cases)} 个接口到 {output_file}")else:print("没有找到有效的接口数据")def export_all_projects_to_excel(self, output_file):"""导出所有项目接口到Excel"""# 获取项目列表project_data = self.get_project_list()if not project_data:print("获取项目列表失败")returnall_test_cases = []projects = project_data.get('list', [])for project in projects:project_id = project.get('_id')project_name = project.get('name')print(f"正在处理项目: {project_name}")# 获取接口列表interfaces = self.get_interface_list(project_id)if not interfaces:continuefor interface in interfaces:interface_id = interface.get('_id')if interface_id:# 获取接口详情detail = self.get_interface_detail(interface_id)test_case_data = self.extract_interface_case_data(detail)if test_case_data:test_case_data['项目名称'] = project_nameall_test_cases.append(test_case_data)# 获取测试用例列表test_cases = self.get_test_case_list(project_id)if test_cases:for test_case in test_cases:test_case_id = test_case.get('_id')if test_case_id:# 获取测试用例详情detail = self.get_test_case_detail(test_case_id)test_collection_data = self.extract_test_collection_data(detail, project_name)if test_collection_data:all_test_cases.append(test_collection_data)# 创建DataFrame并导出到Excelif all_test_cases:df = pd.DataFrame(all_test_cases)# 调整列顺序,将项目名称放在前面cols = df.columns.tolist()if '项目名称' in cols:cols.remove('项目名称')cols.insert(0, '项目名称')df = df[cols]df.to_excel(output_file, index=False)print(f"成功导出 {len(all_test_cases)} 个接口到 {output_file}")else:print("没有找到有效的接口数据")def _generate_request_body_example(self, schema):"""根据JSON Schema生成请求体示例"""if not isinstance(schema, dict) or schema.get('type') != 'object':return json.dumps(schema, ensure_ascii=False, indent=2)properties = schema.get('properties', {})required = schema.get('required', [])# 构建示例请求体example_body = {}for prop_name, prop_info in properties.items():if not isinstance(prop_info, dict):continue# 获取属性类型prop_type = prop_info.get('type', 'string')# 优先使用mock值mock_info = prop_info.get('mock', {})if mock_info and 'mock' in mock_info:example_body[prop_name] = mock_info['mock']else:# 根据类型填充默认值if prop_type == 'string':example_body[prop_name] = ""elif prop_type == 'integer':example_body[prop_name] = 0elif prop_type == 'number':example_body[prop_name] = 0elif prop_type == 'boolean':example_body[prop_name] = Falseelif prop_type == 'array':example_body[prop_name] = []elif prop_type == 'object':example_body[prop_name] = {}else:example_body[prop_name] = ""return json.dumps(example_body, ensure_ascii=False, indent=2)def main():# 直接定义常量YAPI_URL = "http://11.11.11.11:3000/"  # 替换为你的Yapi服务器地址TOKEN = "1234"  # 替换为你的Yapi访问tokenPROJECT_ID = 2680  # 项目ID,如果为None则导出所有项目OUTPUT_FILE = "yapi_test_cases.xlsx"  # 输出Excel文件名# 如果要导出Yapi测试用例集合那么需要去F12 查看cookiescookies = {'_yapi_token': "1234",'_yapi_uid': "1243"}project_name = "国内食材管理"use_test_case = True  # 如果想导出Yapi中测试用例集合那么设置为Trueyapi_client = YapiToExcel(YAPI_URL, TOKEN, cookies, project_name=project_name, use_test_case=use_test_case)if PROJECT_ID:yapi_client.export_project_to_excel(PROJECT_ID, OUTPUT_FILE)else:yapi_client.export_all_projects_to_excel(OUTPUT_FILE)if __name__ == "__main__":main()
http://www.dtcms.com/a/353625.html

相关文章:

  • ProfiNet 转 Ethernet/IP西门子 S7-400 及罗克韦尔 PLC 于原油蒸馏的集成应用
  • 插入排序讲解
  • D‘RespNeT无人机图像分割数据集与YOLOv8-DRN模型,实时识别入口与障碍,助力灾后救援
  • WebConfig的登录与放行
  • 【C语言16天强化训练】从基础入门到进阶:Day 12
  • 归档和压缩
  • 摄像头镜头模组的设计要点
  • ES03-常用API
  • 安装了TortoiseSVN但是在idea的subversion里面找不到svn.exe
  • Dify 从入门到精通(第 59/100 篇):Dify 的自动化测试(进阶篇)
  • Python爬虫实战:构建音乐作品电商平台数据采集与分析系统
  • Highcharts Stock :打造专业级金融图表的利器
  • Apache DolphinScheduler:数据治理中数据质检利器
  • 机器学习 TF-IDF方法
  • 使用MP4视频格式链接地址的自适应视频弹窗实现方案HTML代码
  • 智能体协作体系核心逻辑:Prompt、Agent、Function Calling 与 MCP 解析
  • 流量迷局 - 理解负载均衡(L4/L7)与CDN背后的“隐形路由
  • 全球首款Al勒索软件PromptLock:跨平台攻击新威胁, Windows/macOs/Linux均受影响
  • Python 数据分析学习笔记:Pandas 数据索引
  • 通信协议接口
  • 设计模式8-命令模式
  • docker常用命令有哪些
  • ASM字节码框架和KSP能够解析JAR包或者AAR包里面的内容吗?
  • 碰一碰发视频手机版源码开发:支持OEM
  • 76 最小覆盖子串
  • CPTS-Reddish
  • 【开发配置】云服务器配置Gitlab服务
  • 解决pod install报错问题的一些方法
  • 合金弹头全系列游戏合集分享 电脑安卓手机掌机SWITCH整合版 (1/2/X/3/4/5/6/7/XX)
  • Elasticsearch数据迁移快照方案初探(二):快照创建与多节点存储问题解决