Pytest系列-数据驱动@pytest.mark.parametrize(7)
简介
unittest 和 pytest参数化对比:
pytest与unittest的一个重要区别就是参数化,unittest框架使用的第三方库ddt来参数化的
而pytest框架:
- 前置/后置处理函数fixture,它有个参数params专门与request结合使用来传递参数,也可以用parametrize结合request来传参
- 针对测试方法参数化就直接使用装饰器
@pytest.mark.parametrize来对测试用例进行传参
参数化目的
- 参数化,就是把测试过程中的数据提取出来,通过参数传递不同的数据来驱动用例运行。其实也就是数据驱动的概念
- 当测试用例只有测试数据和期望结果不一样,但操作步骤是一样的时,可以用参数化提高代码复用性,减少代码冗余
参数化实际应用举例
Web UI自动化中的开发场景,比如是一个登录框:
1、需要测试账号空、密码空、账号密码都为空、账号不存在、密码错误、账号密码正确等情况
2、这些用例的区别就在于输入的测试数据和对应的交互结果
3、所以我们可以只写一条登录测试用例,然后把多组测试数据和期望结果参数化,节省很多代码量
Pytest参数化
语法
@pytest.mark.parametrize(args_name,args_values,indirect=False, ids=None,scope=None)
参数列表
- args_name:参数名称,用于参数值传递给函数
- args_values:参数值:(列表和列表字典,元组和字典元组),有n个值那么用例执行n次。
- indirect:默认为False,代表传入的是参数。如果设置成True,则把传进来的参数当函数执行,而不是一个参数。
- ids:自定义测试id,字符串列表,ids的长度需要与测试数据列表的长度一致,标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性
- scope:如果指定,则表示参数的范围。
范围用于按参数实例对测试进行分组。
它还将覆盖任何夹具功能定义的范围,允许使用测试上下文或配置设置动态范围。
使用方法
1、单个参数
@pytest.mark.parametrize() 装饰器接收两个参数,一个参数是以字符串的形式标识用例函数的参数,第二个参数以列表或元组的形式传递测试数据
import pytest
#待测试数据
def add(a,b):return a+b# 单个参数的情况
@pytest.mark.parametrize("a",[1,2,3,4])
def test_add(a): # 作为用例参数,接收装饰器传入的数据print(" a的值:",a)assert add(a,1) == a+1
执行结果

2、多个参数
多个参数,@pytest.mark.parametrize()第一个参数依然是字符串, 对应用例的多个参数,用逗号分隔,实际是一个解包的过程。
import pytestdef add(a,b):return a+b@pytest.mark.parametrize("a,b,c",[(1,2,3),(4,5,9),('1','2','12')])
def test_add(a,b,c):print(f"\n a,b,c的值:{a},{b},{c}")assert add(a,b)==c

执行结果

3、整个测试类参数化
测试类的参数化,其实际上也是对类中的测试方法进行参数化。
当装饰器 @pytest.mark.parametrize 装饰测试类时,会将数据集合传递给类的所有测试用例方法
import pytestdata= [(1,2,3),(4,5,9)]@pytest.mark.parametrize("a,b,c",data)
class TestStudy:def test_parametrize_one(self,a,b,c):print(f"\n 测试函数111 测试数据为 {a}-{b}")assert a+b ==cdef test_parametrize_two(self, a, b, c):print("\n 测试函数222 测试数据为 {}-{}".format(a,b))assert a + b == c
执行结果

4、多个参数叠加相乘
多个参数组合时使用的是笛卡尔积。
笛卡尔积:
- 一个函数或一个类可以装饰多个 @pytest.mark.parametrize
- 这种方式,最终生成的用例数是nm,比如上面的代码就是:参数a的数据有3个,参数b的数据有2个,所以最终的用例数有32=6条
- 当参数化装饰器有很多个的时候,用例数都等于n * n * n* n *…
# 笛卡尔积,组合数据
data_1=[1,2,3]
data_2=['a','b']@pytest.mark.parametrize('a',data_1)
@pytest.mark.parametrize('b',data_2)
def test_parametrize_one(a,b):print(f"笛卡尔积 测试数据为:{a},{b}")
执行结果

参数化,传入字典
# 字典
data_1=({'user':1,'pwd':2},{'user':3,'pwd':4}
)@pytest.mark.parametrize('dic',data_1)
def test_parametrize_1(dic):print(f"测数据为 \n {dic}")print(f"user:{dic['user']},pwd:{dic['pwd']}")
执行结果

参数化,标记数据
# 标记参数化
@pytest.mark.parametrize("test_input,expected",[("3+5",8),("2+4",6),pytest.param("6 * 9",42,marks=pytest.mark.xfail),pytest.param("6 * 6",42,marks=pytest.mark.skip)
])
def test_parametrize_mark(test_input,expected):assert eval(test_input) == expected
执行结果

5、ids 自定义测试id
-
@pytest.mark.parametrize()提供了 ids 参数来自定义显示结果,主要是为了更加清晰看到用例的含义 -
ids的长度需要与测试数据列表的长度一致,与fixture的ids参数是一样的,可参考fixture的ids。
# 增加可读性
data_1=[(1,2,3),(4,5,9)]ids = ["a:{} + b:{} = expect:{}".format(a,b,expect) for a,b,expect in data_1]@pytest.mark.parametrize("a,b,expect",data_1,ids=ids)
class TestParametrize(object):def test_parametrize_1(self,a,b,expect):print(f"测试函数1测试数据为 {a}--{b}")assert a + b ==expectdef test_parametrize_2(self,a,b,expect):print("测试函数2测试数据为 {}--{}".format(a,b))assert a + b == expect
执行结果

request 与parametrize 结合使用给 Fixture传参
-
fixture自身的params参数可以结合request来传参,详见fixture的其他参数介绍章节,当然也可以用parametrize来参数化代替params
-
indirect=True参数,目的是把传入的data当做函数去执行,而不是参数
-
如果测试方法写在类中,则
@pytest.mark.parametrize的参数名称要与@pytest.fixture函数名称保持一致
应用场景:
- 为了提高复用性,我们在写测试用例的时候,会用到不同的fixture,比如:最常见的登录操作,大部分的用- 例的前置条件都是登录
- 假设不同的用例想登录不同的测试账号,那么登录fixture就不能把账号写死,需要通过传参的方式来完成登录操作
1、单个参数
@pytest.fixture()
def test_demo(request):name = request.paramyield nameprint(f"==测试数据是:{name}==")data=["ceshi","qianduan"]
ids=[f"test_name is:{name}" for name in data]@pytest.mark.parametrize("test_demo",data,ids=ids,indirect=True)
def test_name(test_demo):print(f"测试用例的数据是:{test_demo}")
执行结果

知识点:
- 添加 indirect=True 参数是为了把 test_demo 当成一个函数去执行,而不是一个参数并且将data当做参数传入函数
- def test_name(test_demo) ,这里的 test_demo 是获取fixture返回的值
2、多个参数
@pytest.fixture()
def logins(request):param = request.paramyield paramprint(f"账号是:{param['username']},密码是:{param['pwd']}")data =[{"username":"张三","pwd":"123456"},{"username":"李四","pwd":"12345"}
]@pytest.mark.parametrize("logins",data,indirect=True)
def test_name_pwd(logins):print(f"账号是:{logins['username']},密码是:{logins['pwd']}")
执行结果

如果需要传多个参数,需要通过字典去传
3、多个fixture(只加一个装饰器)和多个parametrize(叠加装饰器)
# 多个fixture
@pytest.fixture()
def login_user(request):user = request.paramyield userprint("账号:%s" % user)@pytest.fixture()
def login_pwd(request):pwd = request.paramyield pwdprint("密码:%s" % pwd)data =[{"username":"张三","pwd":"123456"},{"username":"李四","pwd":"12345"}
]@pytest.mark.parametrize("login_user,login_pwd",data,indirect=True)
def test_more_fixture(login_user,login_pwd):print("fixture返回的内容:",login_user,login_pwd)
执行结果

@pytest.fixture(scope="function")
def login_user(request):user = request.paramyield userprint("账号:%s" % user)@pytest.fixture(scope="function")
def login_pwd(request):pwd = request.paramyield pwdprint("密码:%s" % pwd)name= ["张三","李四"]
pwd = ["123456","12345"]@pytest.mark.parametrize("login_user",name,indirect=True)
@pytest.mark.parametrize("login_pwd",pwd,indirect=True)
def test_more_fixture(login_user,login_pwd):print("fixture返回的内容:",login_user,login_pwd)
执行结果

[参考文章] 小菠萝测试笔记
相关文章:
Pytest系列-数据驱动@pytest.mark.parametrize(7)
简介 unittest 和 pytest参数化对比: pytest与unittest的一个重要区别就是参数化,unittest框架使用的第三方库ddt来参数化的 而pytest框架: 前置/后置处理函数fixture,它有个参数params专门与request结合使用来传递参数&#x…...
【Qt】QGroundControl入门2:下载、编译、错误处理、运行
1、源码下载 git clone https://github.com/mavlink/qgroundcontrol.git 2、下载依赖库 2.1 查看依赖库的github路径 cat .gitmodules[submodule "src/GPS/Drivers"]path = src/GPS/Driversurl = https://github.com/PX4/GpsDrivers.git [submodule "libs/m…...
【深度学习】Pytorch 系列教程(十):PyTorch数据结构:2、张量操作(Tensor Operations):(4)索引和切片详解
目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量(Tensor) 2、张量操作(Tensor Operations) 1. 数学运算 2. 统计计算 3. 张量变形 4. 索引和切片 使用索引访问单个元素 使用切片访问子集 使用索引和…...
2024字节跳动校招面试真题汇总及其解答(三)
6.jwt与cookie区别 JWT 和 Cookie 都是用于在客户端和服务器之间传输信息的常用方法。但是,它们之间存在一些关键差异。 JWT 是 JSON Web Token 的缩写,它是一种基于 JSON 的加密令牌。JWT 由三部分组成:Header、Payload 和 Signature。Header 包含令牌的类型、加密算法和…...
基于springboot+vue的便利店信息管理系统
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...
在ubuntu18.04上编译C++版本jsoncpp/opencv/onnxruntime且如何配置CMakelist把他们用起来~
这篇文章背景是笔者在ubuntu上编译C代码,依赖一些包,然后需要编译并配置到CMakelist做的笔记。主要也是一直不太懂CMakellist,做个笔记以防忘记,也给读者提供一站式的参考,可能您需要的不是这几个包,但大同…...
大二上学期学习计划
这个学期主要学习的技术有SpringBoot,Vue,MybatisPlus,redis,还有要坚持刷题,算法不能落下,要坚持一天至少刷2道题目,如果没有布置任务就刷洛谷上面的,有任务的话就尽量完成任务&…...
【python爬虫—星巴克产品】
文章目录 需求爬取星巴克产品以及图片,星巴克菜单 python爬虫爬取结果 需求 爬取星巴克产品以及图片,星巴克菜单 网页分析: 首先,需要分析星巴克官方网站的结构,了解菜单栏的位置、布局以及菜单项的标签或类名等信息…...
shell SQL 变量 Oracle shell调用SQL操作DB
注意 : v\\\$ 用法, “v\\\$session ” ""不能用 sqlplus -S / as sysdba << EOF set pagesize 0 set verify off set feedback off set echo off col coun new_value v_coun select count(*) coun from dual; EOF value"$?"VALUE…...
【校招VIP】java线程池考点之核心线程数
考点介绍: 线程池是这一两年java大厂提问频度飙升的考点,需要从池子的概念理解相关参数和方法 java线程池考点之核心线程数-相关题目及解析内容可点击文章末尾链接查看! 一、考点试题 1、请列举一下启动线程有哪几种方式,之后再…...
[每周一更]-(第61期):Rust入门策略(持续更新)
一门语言的学习,就要从最基本的语法开始认识,再分析不同语言的区别,再加上实战,才能更快的学会,领悟到作者的设计思想; 介绍 Rust编程练习 开发工具VSCode及插件 社区驱动的 rust-analyzerEven Better T…...
线程安全问题的原因及解决方案
要想知道线程安全问题的原因及解决方案,首先得知道什么是线程安全,想给出一个线程安全的确切定义是复杂的,但我们可以这样认为:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,…...
基于matlab中点放炮各类地震波时距曲线程序
完整程序: clear all dx50;x-500:dx:500;%炮检距 h100;V11500; theta25*pi/180; V2V1/sin(theta); t1sqrt(x.*x4*h*h)/V1;%反射波时距曲线 t2abs(x)./V1;%直达波时距曲线 %折射波时距曲线 xm2*h*tan(theta);%求盲区 k1; for i1:length(x) if x(i)<-xm …...
vue中el-dialog 中的内容没有预先加载,因此无法获得内部元素的ref 的解决方案 使用强制提前加载dialog方法
问题描述 在没有进行任何操作的时候,使用 this.$refs.xxxx 无法获取el-dialog中的内部元素,这个问题会导致很多bug,其中目前网络上也有许多关于这个问题的解决方案,但是大多数是使用el-dialog中的open在dialog打开的时候使用thi…...
vue-h5移动Web的rem配置
H5移动的适配方案 rem rem适配方案是兼容性比较好的移动端适配方案,rem支持大部分的移动端系统和机型。 rem是相对于根元素的字体大小的单位。本质上就是一个相对单位,和em的区别是:em是依赖父元素的字体来计算,rem是依赖根元素…...
企业级数据仓库-数仓实战
数仓实战 安装包大小 安装清单 环境搭建 一、环境搭建01(机器准备) 准备好三台虚拟机,并进行修改hostname、在hosts文件增加ip地址和主机名映射 。 1、设置每个虚拟机的hostname vi /etc/sysconfig/network 修改HOSTNAMEnode02修改hostna…...
Spring Boot 下载文件(word/excel等)文件名中文乱码问题|构建打包不存在模版文件(templates等)
Spring Boot 下载文件(word/excel等)文件名中文乱码问题|构建打包不存在模版文件(templates等) 准备文件,这里我放在resource下的templates路径 在pom中配置构建打包的资源,更新maven 如果使用了assembly打包插件这样配置可能仍不生效&#…...
Ansible数组同步至Shell脚本数组中
1、ansible中定义数组,我以 ccaPojectList 数组为例子,如下图数组内容 2、需要写一个j2模板的Shell脚本,在j2模板的Shell脚本中引用ansible的 ccaPojectList 数组,大致如下图: {% for item in ccaPojectList %} "{{ item }…...
私域流量的优势
私域流量是指由自身品牌或个人拥有并具备完全掌控权的流量资源。它相比于传统的广告推广,拥有独特的优势。 首先,私域流量能够更加精准地定位目标用户,实现精准传播。不再盲目投放广告,而是通过建立自身社群、粉丝群,获…...
Java 中“1000==1000”为false,而”100==100“为true?
如果你运行下面的代码: Integer a 1000, b 1000; System.out.println(a b);//1Integer c 100, d 100; System.out.println(c d);//2你会得到: false true基本知识:我们知道,如果两个引用指向同一个对象,用表示它们是相等的。如果两…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
