Pytest自动化发现测试数据并进行数据驱动-支持YAML/JSON/INI/CSV数据文件

news/2024/11/14 5:53:22/文章来源:https://www.cnblogs.com/superhin/p/18542886

需求

  • 在测试框架中,往往需要测试数据和代码分离,使用CSV或JSON等数据文件存储数据,使用代码编写测试逻辑
  • 一个用例过程往往可以测试多组数据,Pytest原生的参数化往往需要我们自己手动读取数据文件,比较麻烦又略显混乱
  • 我们如何能把数据文件按约定的目录和文件名存起来,文件中可以存一组或多组数据,用例自动根据里面的数据进行数据驱动呢?
  • 另外,为了灵活,我们尽量可以支持多种数据类型,如YAML/JSON/INI/CSV等
  • 是否能仅自动化发现测试数据,不启用数据驱动

约定

image

  1. 我们约定,用例使用case_data这个fixture时,可以自动获取到用例对应数据,如
# filename: test_a.py
def test_a_01(case_data):print(case_data)
  1. 我们添加一个自定义参数和配置项 datapath,设定为测试数据的根目录,添加一个ddt参数和配置项,设置是否启用ddt模式,默认不启用,如
# filename: pytest.ini
[pytest]
datapath=testdata
ddt=true
  1. 我们约定 测试用例(测试函数)的数据,存放在 测试数据的根目录/测试文件名/目录下 (暂时忽略模块),测试数据文件名(不包含后缀) 必须 与 测试函数名相同,如 test_a.py中test_a_01用例对应数据
testdata/test_a/test_a_01.yaml
  1. 测试数据文件.yaml/.json/.ini/.csv任选一种,同时加载优先级为 .yaml > .json > .ini > .csv
  2. ini文件 分段名 如 [data1]"为该数据的id标识,并支持自动继承[DEFAULT]段默认数据,如
# filename: test_a_01.ini
[DEFAULT]
age=15[data1]
name=张三[data2]
name=李四
age=16[data3]
name=王五
age=17
  1. json或yaml文件,如为字典格式,则每个key为该数据的id标识,如为列表格式,每组数据中如果有_id字段,则视为数据id标识,如不包含_id,则数据无id标识,如
# filename: test_a_01.yaml
data1:name: 张三age: 15
data2:name: 李四age: 16
data3:name: 张三age: 17

# filename: test_a_01.yaml
- _id: data1name: 张三age: 15
- _id: data2name: 李四age: 16
- _id: data3name: 张三age: 17
  1. csv文件第一行必须字段标题行,如name,age,每组数据中如果有_id字段,则视为数据id标识,如不包含_id,则数据无id标识,如

test_a_01.csv

_id,name,age
data1,张三,15
data2,李四,16
data3,王五,17

实现

实现思路:使用pytest hooks方法pytest_generate_tests来根据数据文件内容动态生成用例
所需依赖:pip install pytest filez pyyaml

  1. 添加自定义配置项
# filename: conftest.py
def pytest_addoption(parser):# 制定测试数据根目录parser.addoption("--datapath", action="store", help="testdata dir path")parser.addini('datapath', help='testdata dir path')# 是否启用数据驱动parser.addoption("--ddt", action="store_true", help="enable data driven test for testdata")parser.addini('ddt', help='enable data driven test for testdata')
  1. 核心实现
# filename: conftest.py
def pytest_generate_tests(metafunc):if "case_data" in metafunc.fixturenames:config = metafunc.configdatapath = config.getoption("--datapath") or config.getini("datapath")ddt = config.getoption("--ddt") or config.getini("ddt")# 如果配置的datapath为绝对路径,则直接视为测试数据根目录if datapath.startswith("/"):testdata_dir = Path(datapath)else:# 如果不是绝对路径则前面添加测试项目根目录testdata_dir = config.rootdir / datapath# 用例文件名(不带扩展名),如test_atestfile_name = metafunc.definition.fspath.purebasename# 用例函数名,如test_a_01testcase_name = metafunc.definition.name# 用例节点id,如test_a.py::test_a_01testcase_node_id = metafunc.definition.nodeid# 读取对应数据文件testcase_csv_datafile = testdata_dir / testfile_name / f'{testcase_name}.csv'testcase_ini_datafile = testdata_dir / testfile_name / f'{testcase_name}.ini'testcase_json_datafile = testdata_dir / testfile_name / f'{testcase_name}.json'testcase_yaml_datafile = testdata_dir / testfile_name / f'{testcase_name}.yaml'if testcase_yaml_datafile.exists():# 读取yaml文件with open(testcase_yaml_datafile) as f:file_data = yaml.safe_load(f)elif testcase_json_datafile.exists():# 读取json文件file_data = file.load(testcase_json_datafile)elif testcase_ini_datafile.exists():# 读取ini文件file_data = file.load(testcase_ini_datafile)elif testcase_csv_datafile.exists():# 读取csv文件-带标题行file_data = file.load(testcase_csv_datafile, header=True)else:return# 对列表和字典格式数据进行处理data, ids = None, Noneif isinstance(file_data, list):data = file_dataif len(file_data) > 0 and file_data[0].get('_id'):ids = [item.get('_id') for item in file_data]data = [item for item in file_data if item!='_id']elif isinstance(file_data, dict):ids = list(file_data.keys())data = list(file_data.values())else:logging.warning(f"测试用例 {testcase_node_id} 数据格式错误, 应为列表或字典格式")if ddt and isinstance(data, list):metafunc.parametrize("case_data", data, ids=ids, scope="function")else:  # 不启用ddt时,整体作为一个数据metafunc.parametrize("case_data", [file_data], scope="function")

用例运行效果如下
image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/832542.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IT Manager项目管理工具-最新版

为了解决项目管理的难点,过多纸质办公的问题,诞生了该系统。其中的价值点包括几大点: 公司组织架构管理;项目成员管理,项目分解,任务分配,时间进度,质量把控; 周报,月报,工时统计;查看项目成员工作饱和度;协助公司进行有效的项目成本控制 组织数据初始化 首先需要…

概率统计-常见分布的均值及方差

概率统计-常见分布的均值及方差 纯原创+老师的PPT总结部分,作二级结论

团队作业4-2

仓库地址:https://github.com/bitpurleclude/GDUT-Goofish.git这个作业属于哪个课程 (https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/join?id=CfDJ8AOXHS93SCdEnLt5HW8VuxT_rAhbZKO3TfjMmbv1B0Re5Fp2d0_QACha2ZoYZ4fxF-ZKCCAhfJl7B8mvCfesLYE02X8T6kx_2R8w0SR-ykrgDVRKW…

【nginx安全】Nginx日志安全分析脚本

Nginx 日志的重要性和必要性 我们知道 Nginx 属于是程序日志的范畴,相对于系统日志来说层级要低一些了,但对于站长来说是至关重要的。因为 Nginx 日志里记录着站点来访的所有信息,无论是正常访客还是恶意请求都会在日志里留下痕迹,比如:被采集、恶意刷流量、暴力破解、漏洞…

MethodImpl优化性能

参数解释 MethodImplOptions.AggressiveInlining:请求编译器在可能的情况下对方法进行内联。 MethodImpl:这是一个属性,允许开发者为方法指定特定的实现行为,比如请求内联、忽略栈追踪等。 内联的作用 内联的主要作用是提升性能,特别是在如下情况下: 消除方法调用开销:通…

五步快速搭建企业客户服务知识库

引言 在当今竞争激烈的市场环境中,高效、准确的客户服务已成为企业赢得客户信任与忠诚度的关键。一个完善的企业客户服务知识库,不仅能够显著提升客服团队的工作效率,还能极大增强客户的满意度与忠诚度。本文将详细介绍五步快速搭建并优化企业客户服务知识库的方法,并特别推…

基于FCM模糊聚类算法的图像分割matlab仿真

1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a3.部分核心程序 (完整版代码包含详细中文注释和操作步骤视频)I_mean = func_median(Im1,Lwin);%% 将图像灰度按列排列 X = Im1(:); X_spatial = I_mean(:);% 初始化标签数组 I_clu…

2024.11.12总结报告(一本“英语八年级上册”TEST4 A完形填空 难度:2)

今日份错误:基本介绍:本题为完形填空选择题,一共10题,错误2题 基本考点:本题考查重点为翻译和理解,难点为语法和词汇 错误题目:(7)(10) 分析:(7) 本小题的错误原因为语法,理解中出现错误,具体为动词的过去式与过去分词并未熟练掌握,上下文的联系不够紧密,对文…

Alpha冲刺阶段博客

数字电路模拟游戏团队 Alpha冲刺阶段博客 一、Scrum Meeting 第六周会议记录 第七周会议记录 二、测试报告 Alpha阶段测试报告 三、习得的软工原理/方法/技能? 1. 迭代开发与持续集成 采用迭代开发模式可以极大的提高开发效率,降低开发成本,迭代开发是一种增量式的软件开发方…

【shell脚本】了解一下shell中的主机变量和本地语系变量

简单介绍一下在 shell 脚本中的主机变量和本地语系变量。 版本和主机信息变量 shell 内置了一些变量,用于记录主机、硬件、操作系统等信息。这些变量如下:本地语系变量这些变量的优先级关系为:LC_ALL > LC_* > LANG ​原创 模糊的程序员

DVWA SQL注入union

数字型注入 1 and 1=1 1 and 1=2 返回数据不一样则有注入点且为数字型注入 //判断列数 ?id=and 1 order by 6 //返回正确 ?id=and 1 order by 7 //返回错误 得到列数为6 查数据库:1 and 1=2 union select 1,database() 字符型注入 and 1=1 and1=1 and 1=2 and1=1 ?id=…

痞子衡嵌入式:关于恩智浦SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是SDK2.0里事务型中断处理函数(DriverIRQHandler)的重定向注意事项。最近有一个 i.MXRT 客户在使用官方 SDK 外设驱动里的中断处理函数时遇到了代码重定向失效问题,客户用得是一个 XIP Flash 工程,想把程序中…