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…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
