【接口自动化连载】使用yaml配置文件自动生成接口case
直接上干货撸代码,有一些是通用的工具类代码,一次性封装永久使用,期待大家的关注,一起加油!!!
配置文件
根据不同的业务需求进行配置,例如Goods服务、Order服务分开配置,每个服务下配置接口信息,每个接口文件里配置各种case。
/conf/GooodsApi/get_shop_info.yaml
# 公共参数
case_common:allureEpic: 商品接口allureFeature: 店铺信息allureStory: 店铺信息get_user_info_01:host: https://goodsapi.e.weibo.comurl: /mp/shop/getShopInfomethod: GETdetail: 获取商家店铺信息headers:
# Content-Type: multipart/form-data;# 这里cookie的值,写的是存入缓存的名称
# cookie: $cache{login_cookie}# 请求的数据,是 params 还是 json、或者file、datarequestType: params# 是否执行,空或者 true 都会执行is_run:data:{"shop_id": xxxx}# 是否有依赖业务,为空或者false则表示没有dependence_case: False# 依赖的数据dependence_case_data:assert:# 断言接口状态码errorCode:jsonpath: $.codetype: ==value: 0AssertType:sql:
通用工具类
文件操作
/utils/file_operate.py
import osdef get_root_path():"""获取(项目)根目录"""return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def ensure_path_sep(path):"""兼容windows和Linux不同环境的操作系统路径"""if '/' in path:path = os.sep.join(path.split('/'))if '\\' in path:path = os.sep.join(path.split('\\'))return get_root_path() + pathdef get_all_yaml_files(file_path, yaml_data_switch=False):"""获取配置的yaml文件路径"""file_name = []for root, dir, files in os.walk(file_path):for _file_path in files:path = os.path.join(root, _file_path)if yaml_data_switch:if 'yaml' in path or '.yml' in path:file_name.append(path)file_name.append(path)return file_name
操作yaml
/utils/yaml_control.py
Class YamlControl:def __init__(self, file_str):self.file_str = file_strdef file_is_exists(self, filepath):if os.path.exists(filepath):return Truereturn Falsedef read_yaml_data(self):"""获取yaml文件数据"""if self.file_is_exists(self.file_str):data = open(self.file_str, "r", encoding="UTF-8")yaml_data = yaml.load(data, Loader = yaml.FullLoader)else:raise FileNotFoundError("文件路径不存在")return yaml_datadef save_yaml_data(self, file_path, data):if self.file_is_exists(file_path):with open(file_path, 'w') as file:yaml.safe_dump(data, file, default_flow_style=False)else:raise FileNotFoundError("文件路径不存在")
自动生成用例代码
/utils/case_automatic_genration.py
import os
from utils.read_file_tools import get_all_yaml_files, ensure_path_sep
from utils.yaml_control import YamlControl
from utils.test_case import write_testcase_fileclass TestCaseAutomaticGeneration:def __init__(self):self.yaml_case_data = Noneself.file_path = None@propertydef allure_epic(self):_allure_epic = self.yaml_case_data.get("case_common").get("allureEpic")assert _allure_epic is not None, ("用例中 allureEpic 为必填项,请检查用例内容, 用例路径:'%s'" % self.file_path)return _allure_epic@propertydef allure_feature(self):_allure_feature = self.yaml_case_data.get("case_common").get("allureFeature")assert _allure_feature is not None, ("用例中 allureFeature 为必填项,请检查用例内容, 用例路径:'%s'" % self.file_path)return _allure_feature@propertydef allure_story(self):_allure_story = self.yaml_case_data.get("case_common").get("allureStory")assert _allure_story is not None, ("用例中 allureStory 为必填项,请检查用例内容, 用例路径:'%s'" % self.file_path)return _allure_story@propertydef case_data_path(self):"""返回 yaml 用例文件路径"""return ensure_path_sep("/conf")@propertydef gen_file_name(self):"""生成文件名 将.yaml替换成.py"""# 例 /get_shop_info.yaml——>/get_shop_info.py# 获取配置文件相对路径l = len(self.case_data_path)yaml_path = self.file_path[l:]file_name = Noneif '.yaml' in yaml_path:file_name = yaml_path.replace('.yaml', '.py')elif '.yml' in yaml_path:file_name = yaml_path.replace('.yml', '.py')return file_name@propertydef get_test_class_title(self):"""自动生成类名"""# 例 get_shop_info——>GetShopInfo_file_name = os.path.split(self.gen_file_name)[1][:-3]_name = _file_name.split("_")_name_len = len(_name)for i in range(_name_len):_name[i] = _name[i].capitalize()_class_name = "".join(_name)return _class_name@propertydef get_func_title(self):"""自动生成方法名"""return os.path.split(self.gen_file_name)[1][:-3]@propertydef spilt_path(self):# 使用"/"分割 获取文件名称path = self.gen_file_name.split(os.sep)path[-1] = path[-1].replace(path[-1], "test_" + path[-1])return path@propertydef get_case_path(self):"""生成测试用例目录"""# 相对路径 test_case/x/test_get_shop_info.pyreturn ensure_path_sep("/test_case" + os.sep.join(self.spilt_path)) @propertydef case_ids(self):return [k for k in self.yaml_case_data.keys() if k != "case_common"]@propertydef get_file_name(self):# 这里通过"/" 符号进行分割,提取出来文件名称# 判断生成的 testcase 文件名称,需要以test_ 开头case_name = self.spilt_path[-1].replace(self.spilt_path[-1], "test_" + self.spilt_path[-1])return case_namedef mk_dir(self) -> None:""" 判断生成自动化代码的文件夹路径是否存在,如果不存在,则自动创建 """# _LibDirPath = os.path.split(self.libPagePath(filePath))[0]_case_dir_path = os.path.split(self.get_case_path)[0]if not os.path.exists(_case_dir_path):os.makedirs(_case_dir_path)def get_case_automatic(self):"""自动生成测试用例代码"""# 获取配置文件下全部yaml文件file_path = get_all_yaml_files(ensure_path_sep("/conf"), yaml_data_switch=True)for file in file_path:# 判断代理拦截的yaml文件,不生成test_case代码if 'proxy_data.yaml' not in file:# 获取配置yaml用例数据self.yaml_case_data = YamlControl(file).read_yaml_data()# yaml文件相对路径self.file_path = file# 判断用例需要用的文件夹路径是否存在,不存在则创建self.mk_dir()print(self.gen_file_name, "\n",self.get_test_class_title,"\n",self.get_func_title,"\n",self.get_case_path,"\n",self.case_ids,"\n",self.get_file_name)write_testcase_file(allure_epic = self.allure_epic,allure_feature=self.allure_feature,allure_story=self.allure_story,class_title=self.get_test_class_title,func_title=self.get_func_title,case_path=self.get_case_path,case_ids=self.case_ids,file_name=self.get_file_name)
下一篇介绍用例内容写入/utils/write_testcase_file.py,使用pytest实现自动化
相关文章:
【接口自动化连载】使用yaml配置文件自动生成接口case
直接上干货撸代码,有一些是通用的工具类代码,一次性封装永久使用,期待大家的关注,一起加油!!! 配置文件 根据不同的业务需求进行配置,例如Goods服务、Order服务分开配置࿰…...
前端安全 常见的攻击类型及防御措施
1. 跨站脚本攻击(XSS) 描述:跨站脚本(XSS:Cross-Site Scripting)是一种安全漏洞,允许攻击者向网站注入恶意客户端代码。该代码由受害者执行从而让攻击者绕过访问控制并冒充用户。XSS攻击可以分…...
来道面试题——CopyOnWriteArrayList
原理 初始化时候,CopyOnWriteArrayList内部维护了一个可变数组,用于存储元素当执行数据变更操作的时候,会先创建一个原数组的副本,在副本上进行写操作,修改副本中的元素。写操作完成之后,把原数组的引用指…...
【Rust自学】5.1. 定义并实例化struct
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 5.1.1. 什么是struct struct的中文意思为结构体,它是一种自定义的数据类型,它允许程序为相关联的值命名和打包&am…...
React 生命周期完整指南
React 生命周期完整指南 1. 生命周期概述 1.1 React 16.3 之前的生命周期 初始化阶段 constructorcomponentWillMountrendercomponentDidMount 更新阶段 componentWillReceivePropsshouldComponentUpdatecomponentWillUpdaterendercomponentDidUpdate 卸载阶段 componentWil…...
python中os._exit(0) 强制关闭进程后来杀死线程
在 Python 中调用 os._exit(0) 会强制终止整个进程,包括所有正在运行的线程。以下是详细解释: os._exit(0) 的行为 立即终止进程:os._exit() 函数会立即终止当前进程,不会执行任何清理操作,如调用清理处理程序&#…...
LeetCode:257. 二叉树的所有路径
跟着carl学算法,本系列博客仅做个人记录,建议大家都去看carl本人的博客,写的真的很好的! 代码随想录 LeetCode:257. 二叉树的所有路径 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根…...
RSICV国产芯片之CHV208
1. 芯片选型分析的对比维度 分析或者对标应用的芯片替代思路 1.1 内核/主频/存储空间支持 内核能力/指令集支持(考虑工具链兼容性); 主频:对比计算能力是否满足基本要求 存储:内存--数据搬移空间决定数据运算的…...
理解神经网络
神经网络是一种模拟人类大脑工作方式的计算模型,是深度学习和机器学习领域的基础。 基本原理 神经网络的基本原理是模拟人脑神经系统的功能,通过多个节点(也叫神经元)的连接和计算,实现非线性模型的组合和输出。每个…...
Android 之 List 简述
一、简单创建方式 Android 开发中,列表有很多种类,如ArrayList、LinkedList、List、MutableList等,创建列表的方式如下所示: fun listDemo() {// 使用 listOf 创建不可变的空列表val list listOf<Int>()val list1 listOf…...
设计模式の中介者发布订阅备忘录模式
文章目录 前言一、中介者模式二、发布订阅模式三、备忘录模式 前言 本篇是关于设计模式中介者模式、观察者(发布-订阅)模式、以及备忘录模式的学习笔记。 一、中介者模式 中介者模式是一种行为型设计模式,其核心目的是为了减少对象之间的复杂…...
云手机群控能用来做什么?
随着云手机的发展,云手机群控技术逐渐从小众的游戏多开工具,发展为涵盖多个领域的智能操作平台。不论是手游搬砖、短视频运营,还是账号养成等场景,云手机群控都展现出了强大的应用潜力。本文将为大家详细解析云手机群控的应用场景…...
fpgafor循环语句使用
genvar i;//循环变量名称 generate for(i0;i<4;ii1)begin:tx//自己定义名称 //循环内容 end endgenerate12位的16进制乘以4就是48位位宽的2进制 因为 222*2(2^4)16...
【FastAPI】BaseHTTPMiddleware类
一、概述 在FastAPI中,BaseHTTPMiddleware 类是Starlette框架提供的一个抽象基类,它允许开发者基于HTTP请求/响应接口编写ASGI中间件。 这个类对于希望实现自定义中间件逻辑的开发者来说是非常重要的工具。 通过继承 BaseHTTPMiddleware 并实现特定的方…...
Solon v3.0.5 发布!(Spring 可以退休了吗?)
Solon 框架! 新一代,面向全场景的 Java 应用开发框架。从零开始构建(非 java-ee 架构),有灵活的接口规范与开放生态。 追求: 更快、更小、更简单提倡: 克制、高效、开放、生态 有什么特点&am…...
网络安全攻防演练中的常见计策
大家觉得有意义记得关注和点赞!!! 引言 在网络安全攻防演练里面,用于分析攻击者动机和行为的,国外的有基于攻击链分析的模型(如Cyber Kill Chain和ATT&CK)和基于威胁行为的模型(…...
SD卡模块布局布线设计
1、SD/TF/SIM卡的定义 2、SD/TF/SIM卡模块引脚定义以及图示 3、SD/TF/SIM卡接口布局和布线 4、小结 1、BGA两线交叉时,可以在源头将两线互相短路连接,然后再输出口删除一小节线,然后CHRLX/V,这样就可以换两条线的网络,…...
Flask-----SQLAlchemy教程
存session session[username] username # 存储数据到 session 取session username session.get(username) render_template return render_template(index.html, usernameAlice),渲染一个包含 username 变量的模板。 redirect return redirect(url_for(profil…...
STM32 高级 物联网通信之CAN通讯
目录 CAN通讯介绍 物理层 协议层 CAN的帧(报文)种类 1 数据帧(发送单元->接受单元) 2 远程帧(接受单元->发送单元) 3 错误帧(发送方发送数据错误会发送的状态帧) 4 过载帧(接收方放不下会发送到的状态帧) 5 帧间隔(状态) 数据帧介绍 远程帧介绍 C…...
“乡村探索者”:村旅游网站的移动应用开发
3.1 可行性分析 从三个不同的角度来分析,确保开发成功的前提是有可行性分析,只有进行提前分析,符合程序开发流程才不至于开发过程的中断。 3.1.1 技术可行性 在技术实现层次,分析了好几种技术实现方法,并且都有对应的成…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...
Vue3中的computer和watch
computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...
针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...
Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
