Python测试框架Pytest的参数化详解

上篇博文介绍过,Pytest是目前比较成熟功能齐全的测试框架,使用率肯定也不断攀升。
在实际工作中,许多测试用例都是类似的重复,一个个写最后代码会显得很冗余。这里,我们来了解一下@pytest.mark.parametrize装饰器,可以很好解决上述问题。
源代码分析
-
def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None): -
""" Add new invocations to the underlying test function using the list -
of argvalues for the given argnames. Parametrization is performed -
during the collection phase. If you need to setup expensive resources -
see about setting indirect to do it rather at test setup time. # 使用给定argnames的argValue列表向基础测试函数添加新的调用,在收集阶段执行参数化。 -
:arg argnames: a comma-separated string denoting one or more argument -
names, or a list/tuple of argument strings. # 参数名:使用逗号分隔的字符串,列表或元祖,表示一个或多个参数名 -
:arg argvalues: The list of argvalues determines how often a -
test is invoked with different argument values. If only one -
argname was specified argvalues is a list of values. If N -
argnames were specified, argvalues must be a list of N-tuples, -
where each tuple-element specifies a value for its respective -
argname. # 参数值:只有一个argnames,argvalues则是值列表。有N个argnames时,每个元祖对应一组argnames,所有元祖组合成一个列表 -
:arg indirect: The list of argnames or boolean. A list of arguments' -
names (self,subset of argnames). If True the list contains all names from -
the argnames. Each argvalue corresponding to an argname in this list will -
be passed as request.param to its respective argname fixture -
function so that it can perform more expensive setups during the -
setup phase of a test rather than at collection time. -
:arg ids: list of string ids, or a callable. -
If strings, each is corresponding to the argvalues so that they are -
part of the test id. If None is given as id of specific test, the -
automatically generated id for that argument will be used. -
If callable, it should take one argument (self,a single argvalue) and return -
a string or return None. If None, the automatically generated id for that -
argument will be used. -
If no ids are provided they will be generated automatically from -
the argvalues. # ids:字符串列表,可以理解成标题,与用例个数保持一致 -
:arg scope: if specified it denotes the scope of the parameters. -
The scope is used for grouping tests by parameter instances. -
It will also override any fixture-function defined scope, allowing -
to set a dynamic scope using test context or configuration. -
# 如果指定,则表示参数的范围。作用域用于按参数实例对测试进行分组。 -
它还将覆盖任何fixture函数定义的范围,允许使用测试上下文或配置设置动态范围。 -
"""
argnames
释义:参数名称。
格式:字符串"arg1,arg2,arg3"。
aegvalues
释义:参数值列表。
格式:必须是列表,如[val1,val2,val3]。
-
单个参数,里面是值的列表,如@pytest.mark.parametrize("name",["Jack","Locus","Bill"]);
-
多个参数,需要用元祖来存放值,一个元祖对应一组参数的值,如@pytest.mark.parametrize("user,age",[("user1",15),("user2",24),("user3",25)])。
ids
释义:可以理解为用例的id。
格式:字符串列表,如["case1","case2","case3"]。
indirect
释义:当indirect=True时,若传入的argnames是fixture函数名,此时fixture函数名将成为一个可执行的函数,argvalues作为fixture的参数,执行fixture函数,最终结果再存入request.param。
当indirect=False时,fixture函数只作为一个参数名给测试收集阶段调用。
备注:这里可以将the setup phase(测试设置阶段)理解为配置 conftest.py 阶段,将the collection phase(测试收集阶段)理解为用例执行阶段。
装饰测试类
-
import pytest -
data = [ -
(2,2,4), -
(3,4,12) -
] -
def add(a,b): -
return a * b -
@pytest.mark.parametrize('a,b,expect',data) -
class TestParametrize(object): -
def test_parametrize_1(self,a,b,expect): -
print('\n测试函数1测试数据为\n{}-{}'.format(a,b)) -
assert add(a,b) == expect -
def test_parametrize_2(self,a,b,expect): -
print('\n测试函数2测试数据为\n{}-{}'.format(a,b)) -
assert add(a,b) == expect -
if __name__ == "__main__": -
pytest.main(["-s","test_07.py"])
-
============================= test session starts ============================= -
platform win32 -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -
rootdir: D:\AutoCode -
plugins: html-3.1.1, metadata-1.11.0 -
collecting ... collected 4 items -
test_07.py::TestParametrize::test_parametrize_1[2-2-4] -
测试函数1测试数据为 -
2-2 -
PASSED -
test_07.py::TestParametrize::test_parametrize_1[3-4-12] -
测试函数1测试数据为 -
3-4 -
PASSED -
test_07.py::TestParametrize::test_parametrize_2[2-2-4] -
测试函数2测试数据为 -
2-2 -
PASSED -
test_07.py::TestParametrize::test_parametrize_2[3-4-12] -
测试函数2测试数据为 -
3-4 -
PASSED -
============================== 4 passed in 0.12s ============================== -
Process finished with exit code 0
由以上代码可以看到,当装饰器装饰测试类时,定义的数据集合会被传递给类的所有方法。
装饰测试函数
单个数据
-
import pytest -
data = ["Rose","white"] -
@pytest.mark.parametrize("name",data) -
def test_parametrize(name): -
print('\n列表中的名字为\n{}'.format(name)) -
if __name__ == "__main__": -
pytest.main(["-s","test_07.py"])
-
============================= test session starts ============================= -
platform win32 -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -
rootdir: D:\AutoCode -
plugins: html-3.1.1, metadata-1.11.0 -
collected 2 items -
test_07.py -
列表中的名字为 -
Rose -
. -
列表中的名字为 -
white -
. -
============================== 2 passed in 0.09s ============================== -
Process finished with exit code 0
当测试用例只需要一个参数时,我们存放数据的列表无序嵌套序列,@pytest.mark.parametrize("name", data) 装饰器的第一个参数也只需要一个变量接收列表中的每个元素,第二个参数传递存储数据的列表,那么测试用例需要使用同名的字符串接收测试数据(实例中的name)且列表有多少个元素就会生成并执行多少个测试用例。
一组数据
-
import pytest -
data = [ -
[1, 2, 3], -
[4, 5, 9] -
] # 列表嵌套列表 -
# data_tuple = [ -
# (1, 2, 3), -
# (4, 5, 9) -
# ] # 列表嵌套元组 -
@pytest.mark.parametrize('a, b, expect', data) -
def test_parametrize_1(a, b, expect): # 一个参数接收一个数据 -
print('\n测试数据为\n{},{},{}'.format(a, b, expect)) -
actual = a + b -
assert actual == expect -
@pytest.mark.parametrize('value', data) -
def test_parametrize_2(value): # 一个参数接收一组数据 -
print('\n测试数据为\n{}'.format(value)) -
actual = value[0] + value[1] -
assert actual == value[2] -
if __name__ == "__main__": -
pytest.main(["-s","test_07.py"])
-
============================= test session starts ============================= -
platform win32 -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 -
rootdir: D:\AutoCode -
plugins: html-3.1.1, metadata-1.11.0 -
collected 4 items -
test_07.py -
测试数据为 -
1,2,3 -
. -
测试数据为 -
4,5,9 -
. -
测试数据为 -
[1, 2, 3] -
. -
测试数据为 -
[4, 5, 9] -
. -
============================== 4 passed in 0.09s ============================== -
Process finished with exit code 0
当测试用例需要多个数据时,我们可以使用嵌套序列(嵌套元组&嵌套列表)的列表来存放测试数据。
装饰器@pytest.mark.parametrize()可以使用单个变量接收数据,也可以使用多个变量接收,同样,测试用例函数也需要与其保持一致。
当使用单个变量接收时,测试数据传递到测试函数内部时为列表中的每一个元素或者小列表,需要使用索引的方式取得每个数据。当使用多个变量接收数据时,那么每个变量分别接收小列表或元组中的每个元素列表嵌套多少个多组小列表或元组,测生成多少条测试用例。
组合数据
-
import pytest -
data_1 = [1,2,3] -
data_2 = ['a','b'] -
@pytest.mark.parametrize('a',data_1) -
@pytest.mark.parametrize('b',data_2) -
def test_parametrize_1(a,b): -
print(f'笛卡尔积测试结果为:{a},{b}') -
if __name__ == '__main__': -
pytest.main(["-vs","test_06.py"])

通过测试结果,我们不难分析,一个测试函数还可以同时被多个参数化装饰器装饰,那么多个装饰器中的数据会进行交叉组合的方式传递给测试函数,进而生成n * n个测试用例。
标记用例
-
import pytest -
@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_mark(test_input,expected): -
assert eval(test_input) == expected -
if __name__ == '__main__': -
pytest.main(["-vs","test_06.py"])

输出结果显示收集到4个用例,两个通过,一个被跳过,一个标记失败:
-
当我们不想执行某组测试数据时,我们可以标记skip或skipif;
-
当我们预期某组数据会执行失败时,我们可以标记为xfail等。
嵌套字典
-
import pytest -
data = ( -
{ -
'user': "name1", -
'pwd': 123 -
}, -
{ -
'user': "name2", -
'pwd': 456 -
} -
) -
@pytest.mark.parametrize('dic',data) -
def test_parametrize(dic): -
print('\n测试数据为\n{}'.format(dic)) -
if __name__ == '__main__': -
pytest.main(["-vs","test_06.py"])

增加测试结果可读性
参数化装饰器有一个额外的参数ids,可以标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性,我们可以标记每一个测试用例使用的测试数据是什么,适当的增加一些说明。
在使用前你需要知道,ids参数应该是一个字符串列表,必须和数据对象列表的长度保持一致。
-
import pytest -
data_1 = [ -
(1, 2, 3), -
(4, 5, 9) -
] -
ids = ["a:{} + b:{} = expect:{}".format(a, b, expect) for a, b, expect in data_1] -
def add(a, b): -
return a + b -
@pytest.mark.parametrize('a, b, expect', data_1, ids=ids) -
class TestParametrize(object): -
def test_parametrize_1(self, a, b, expect): -
print('\n测试函数1测试数据为\n{}-{}'.format(a, b)) -
assert add(a, b) == expect -
def test_parametrize_2(self, a, b, expect): -
print('\n测试函数2数据为\n{}-{}'.format(a, b)) -
assert add(a, b) == expect -
if __name__ == '__main__': -
pytest.main(["-v","test_06.py"])
-
不加ids参数的返回结果:

-
加ids参数的返回结果:

我们可以看到带ids参数的返回结果中的用例都被一个列表明确的标记了,而且通过这种标记可以更加直观的看出来,每个测试用例使用的数据名称及测试内容。
行动吧,在路上总比一直观望的要好,未来的你肯定会感 谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入扣群: 320231853,里面有各种软件测试+开发资料和技术可以一起交流学习哦。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

相关文章:
Python测试框架Pytest的参数化详解
上篇博文介绍过,Pytest是目前比较成熟功能齐全的测试框架,使用率肯定也不断攀升。 在实际工作中,许多测试用例都是类似的重复,一个个写最后代码会显得很冗余。这里,我们来了解一下pytest.mark.parametrize装饰器&…...
KernelSU 如何不通过模块,直接修改系统分区
刚刚看了术哥发的视频,发现kernelSU通过挂载OverlayFS实现无需模块,即可直接修改系统分区,很是方便,并且安全性也很高,于是便有了这篇文章。 下面的教程与原视频存在差异,建议观看原视频后再结合本文章进行操作。 在未进行修改前,我们打开/system/文件夹,并在里面创建…...
红日靶场ATTCK 1通关攻略
环境 拓扑图 VM1 web服务器 win7(192.168.22.129,10.10.10.140) VM2 win2003(10.10.10.135) VM3 DC win2008(10.10.10.138) 环境搭建 win7: 设置内网两张网卡,开启…...
CellMarker | 人骨骼肌组织细胞Marker大全!~(强烈建议火速收藏!)
1写在前面 分享一下最近看到的2篇paper关于骨骼肌组织的细胞Marker,绝对的Atlas级好东西。👍 希望做单细胞的小伙伴觉得有用哦。😏 2常用marker(一) general_mrkrs <- c( MYH7, TNNT1, TNNT3, MYH1, MYH2, "C…...
游戏名台词大赏
文章目录 原神(圈内) 崩坏:星穹铁道(圈内) 崩坏3(圈内) 原神 只要不失去你的崇高,整个世界都会为你敞开。 总会有地上的生灵,敢于直面雷霆的威光。 谁也没有见过风&…...
OpenCV如何在图像中寻找轮廓(60)
返回:OpenCV系列文章目录(持续更新中......) 上一篇:OpenCV如何模板匹配(59) 下一篇 :OpenCV检测凸包(61) 目标 在本教程中,您将学习如何: 使用 OpenCV 函数 cv::findContours使用 OpenCV 函数 cv::d rawContours …...
java 泛型题目讲解
泛型的知识点 泛型仅存在于编译时期,编译期间JAVA将会使用Object类型代替泛型类型,在运行时期不存在泛型;且所有泛型实例共享一个泛型类 public class Main{public static void main(String[] args){ArrayList<String> list1new Arra…...
pptx 文件版面分析-- python-pptx(python 文档解析提取)
安装 pip install python-pptx -i https://pypi.tuna.tsinghua.edu.cn/simple --ignore-installedpptx 解析代码实现 from pptx import Presentation file_name "rag_pptx/test1.pptx" # 打开.pptx文件 ppt Presentation(file_name) for slide in ppt.slides:#pr…...
http的basic 认证方式
写在前面 本文看下http的basic auth认证方式。 1:什么是basic auth认证 basic auth是一种http协议规范中的一种认证方式,即一种证明你就是你的方式。更进一步的它是一种规范,这种规范是这样子,如果是服务端使用了basic auth认证…...
【信息系统项目管理师练习题】信息系统治理
IT治理的核心是关注以下哪项内容? a) 人员培训和发展计划 b) IT定位和信息化建设与数字化转型的责权利划分 c) 业务流程的绩效管理 d) IT基础设施的优化利用 答案: b) IT定位和信息化建设与数字化转型的责权利划分 IT治理体系框架的组成部分包括以下哪些? a) IT战略目标、IT治…...
RabbitMQ之顺序消费
什么是顺序消费 例如:业务上产生者发送三条消息, 分别是对同一条数据的增加、修改、删除操作, 如果没有保证顺序消费,执行顺序可能变成删除、修改、增加,这就乱了。 如何保证顺序性 一般我们讨论如何保证消息的顺序性&…...
轻松上手的LangChain学习说明书
一、Langchain是什么? 如今各类AI模型层出不穷,百花齐放,大佬们开发的速度永远遥遥领先于学习者的学习速度。。为了解放生产力,不让应用层开发人员受限于各语言模型的生产部署中…LangChain横空出世界。 Langchain可以说是现阶段…...
【论文笔记】Training language models to follow instructions with human feedback A部分
Training language models to follow instructions with human feedback A 部分 回顾一下第一代 GPT-1 : 设计思路是 “海量无标记文本进行无监督预训练少量有标签文本有监督微调” 范式;模型架构是基于 Transformer 的叠加解码器(掩码自注意…...
嵌入式交叉编译:x265
下载 multicoreware / x265_git / Downloads — Bitbucket 解压编译 BUILD_DIR${HOME}/build_libs CROSS_NAMEaarch64-mix210-linuxcd build/aarch64-linuxmake cleancmake \-G "Unix Makefiles" \-DCMAKE_C_COMPILER${CROSS_NAME}-gcc \-DCMAKE_CXX_COMPILER${CR…...
一、Redis五种常用数据类型
Redis优势: 1、性能高—基于内存实现数据的存储 2、丰富的数据类型 5种常用,3种高级 3、原子—redis的所有单个操作都是原子性,即要么成功,要么失败。其多个操作也支持采用事务的方式实现原子性。 Redis特点: 1、支持…...
C语言动态内存管理malloc、calloc、realloc、free函数、内存泄漏、动态内存开辟的位置等的介绍
文章目录 前言一、为什么存在动态内存管理二、动态内存函数的介绍1. malloc函数2. 内存泄漏3. 动态内存开辟位置4. free函数5. calloc 函数6. realloc 函数7. realloc 传空指针 总结 前言 C语言动态内存管理malloc、calloc、realloc、free函数、内存泄漏、动态内存开辟的位置等…...
最近惊爆谷歌裁员
Python团队还没解散完,谷歌又对Flutter、Dart动手了。 什么原因呢,猜测啊。 谷歌裁员Python的具体原因可能是因为公司在进行技术栈的调整和优化。Python作为一种脚本语言,在某些情况下可能无法提供足够的性能或者扩展性,尤其是在…...
音频可视化:原生音频API为前端带来的全新可能!
音频API是一组提供给网页开发者的接口,允许他们直接在浏览器中处理音频内容。这些API使得在不依赖任何外部插件的情况下操作和控制音频成为可能。 Web Audio API 可以进行音频的播放、处理、合成以及分析等操作。借助于这些工具,开发者可以实现自定义的音…...
【中等】保研/考研408机试-动态规划1(01背包、完全背包、多重背包)
背包问题基本上都是模板题,重点:弄熟多重背包模板 dp[j]max(dp[j-v[i]]w[i],dp[j]) //核心思路代码(一维数组版) dp[i][j]max(dp[i-1][j], dp[i-1][j-v[i]]w[i])//二维数字版 一、 0-1背包 一般输入两个变量:体积&…...
[DEMO]给两个字符串取交集的词语
要求:2个英文字符串中,取相同的大于等于4个字母的词组 比如: 字符串1:" xingMeiLingabcdef WorldHello", 字符串2:"mnjqlup WorldLingLing xingMeiLingHello" 获取交接: [xingMeiLing…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
