详解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参数的返回结果中的用例都被一个列表明确的标记了,而且通过这种标记可以更加直观的看出来,每个测试用例使用的数据名称及测试内容。

同时,在这我为大家准备了一份软件测试视频教程(含面试、接口、自动化、性能测试等),就在下方,需要的可以直接去观看。

字节大佬,一周讲完,自动化测试项目实战,这套教程是怎么称霸B站的?【2024最新版】

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】Diffusion扩散模型原理解析2

由于篇幅受限,CSDN不能发布超过一定次数的文章,故在此给出上一篇链接:【深度学习】diffusion原理解析 3.2、目标函数求解 里面的最后一项, q ( x T ∣ x 0 ) q(x_T|x_0) q(xT​∣x0​)我们前面提到过,其近似服从标准…

flowable多对并发网关跳转的分析

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: h…

C++:虚函数表Hook

Hook 在计算机编程中,"Hook"(钩子)是一种技术,用于拦截并修改特定事件或函数的执行流程。它允许程序员在特定的代码点插入自定义的代码,以实现对程序行为的修改、监视或增强。 虚函数表Hook 虚函数表&#…

控制台打印空数组展开有数据

控制台打印空数组展开有数据 控制台显示: 代码如下: export const getDict1 (dictCode) > {let list []queryDict({ dictCode }).then(({data}) > {list.push( ...data.map(item > ({ label: item.itemText, value: item.itemValue })))})c…

目标检测算法YOLOv7简介

YOLOv7由Chien-Yao Wang等人于2022年提出,论文名为:《YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors》,论文见:https://arxiv.org/pdf/2207.02696 ,项目网页&#xff…

解决 git 因输入密码错误而导致的报错无法推送问题

报错内容如下: > git push origin master:master fatal: unable to access https://gitee.com/spring-in-huangxian-county/web-tts-vue.git/: OpenSSL SSL_connect: Connection was reset in connection to gitee.com:443 出错原因 根本原因是本机存储的 账户…

大型动作模型 (LAM):AI 驱动的交互的下一个前沿

1.概述 现在人工智能中几个关键的领域,包括生成式人工智能(Generative AI)、大型动作模型(Large Action Models, LAM)、以及交互式人工智能(Interactive AI)。以下是对这些概念的简要解释和它们…

数据库管理-第187期 23ai:怎么用SQL创建图(20240510)

数据库管理187期 2024-05-10 数据库管理-第187期 23ai:怎么用SQL创建图(20240510)1 安装PGX1.1 数据库配置对应用户1.2 使用RPM包安装Graph Server1.3 安装Oracle Graph Client1.4 访问PGX页面 2 SQL Property Graph2.1 创建SQL属性图2.2 关于点和边图元…

c++11 标准模板(STL)本地化库 - 平面类别(std::money_put) - 格式化货币值为字符序列以输出

本地化库 本地环境设施包含字符分类和字符串校对、数值、货币及日期/时间格式化和分析&#xff0c;以及消息取得的国际化支持。本地环境设置控制流 I/O 、正则表达式库和 C 标准库的其他组件的行为。 平面类别 格式化货币值为字符序列以输出 std::money_put template< …

聊聊ChatGPT:智能语言模型背后的原理

目录 1. ChatGPT的基础&#xff1a;GPT模型 2. 预训练与微调&#xff1a;让模型更加智能 2.1 预训练 2.2 微调 3. 多样化的应用场景 4. 未来的展望 5. 结语 在当今的人工智能领域&#xff0c;OpenAI的ChatGPT无疑是一个炙手可热的话题。它不仅能流畅地进行对话&#xff…

【ArcGISProSDK】condition属性

示例 通过caption属性可以看出esri_mapping_openProjectCondition的条件是一个工程被打开 condition的作用 由此可知示例中的Tab实在工程被打开才能使用&#xff0c;否则他禁用显示灰色&#xff0c;在未禁用的时候说明条件满足。 参考文档 insertCondition 元素 (arcgis.com…

局域网手机端远程控制手机

局域网手机端远程控制手机 随着科技的进步和智能设备的普及&#xff0c;远程控制技术在日常生活与工作中的应用越来越广泛。其中&#xff0c;局域网内的手机端远程控制手机技术&#xff0c;因其便捷性和实用性&#xff0c;受到了众多用户的关注。本文将简要介绍该技术及其应用…

#兼职副业赚钱吗?# 宝妈与上班族在水牛社的财富探索

在这个繁忙的都市节奏中&#xff0c;宝妈与上班族都面临着平衡家庭与经济的挑战。那么&#xff0c;兼职副业真的能为他们带来额外的收入吗&#xff1f;接下来&#xff0c;让我们通过两个实例&#xff0c;揭示宝妈和上班族是如何在水牛社找到兼职副业赚钱的契机的。 ✨ 宝妈的故…

Prompt|Kimi高阶技巧,99%的人都不知道

大家好&#xff0c;我是无界生长。 今天分享一条咒语&#xff0c;轻松让Kimi帮你生成流程图&#xff0c;学会了的话&#xff0c;点赞收藏起来吧&#xff01; 效果展示 我们演示一下让kimi帮忙绘制 关注微信公众号“无界生长”的流程图&#xff0c;最终效果图如下所示 效果还不…

Dijkstra求最短路 I:图解 详细代码(图解)

文章目录 题目&#xff1a;Dijkstra求最短路思路伪代码&#xff1a;代码优化优化代码&#xff1a;Java代码 总结 题目&#xff1a;Dijkstra求最短路 给定一个 n个点 m条边的有向图&#xff0c;图中可能存在重边和自环&#xff0c;所有边权均为正值。 请你求出 1号点到 n号点的…

权限束缚术--权限提升你需要知道这些

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要对渗透测试中权限提升的一些基础知识进行整理 并不包含权限提升的具体操作 适合要入门权限提升的朋友 提权的重要性 我们在渗透网站时&#xff0c;我们往往会拿到一些权限&#xff0c;但是我们的权限有…

视频批量剪辑指南:一键合并视频并添加背景音乐,高效便捷

在数字化时代&#xff0c;视频剪辑已经成为了一项常见且重要的技能。无论是制作家庭影片、工作展示还是社交媒体内容&#xff0c;掌握高效的视频剪辑技巧都能极大地提升我们的工作效率和创作质量。本文将为您介绍云炫AI智剪中高效的视频批量剪辑方法&#xff0c;让您能够一键合…

ubantu安装docker以及docker-compose

ubantu安装docker以及docker-compose 安装docker1、从官方存储库中安装Docker2、启动Docker服务3、验证 安装docker compose使用docker部署服务1、需要再opt文件夹下创建以下文件夹&#xff0c;/opt文件夹目录说明2、可将已备份对应文件夹拷至对应文件夹下3、在/opt/compose目录…

linux打包流程

因为linux有俩个python版本&#xff0c;我们需要切换到python3这个版本&#xff0c;默认是python 2.7 alias pythonpython3 切换到python3 再次执行&#xff1a;python -V 显示出python的版本了&#xff0c;然后查看pip的配置&#xff0c;我们打包里面需要的第三方需要放到pip…

Gradient发布支持100万token的Lllama3,上下文长度从8K扩展到1048K

前言 近日Gradient公司在Crusoe Energy公司的算力支持下&#xff0c;开发了一款基于Llama-3的大型语言模型。这款新模型在原Llama-3 8B的基础上&#xff0c;将上下文长度从8000 token大幅扩展到超过104万token。 这一创新性突破&#xff0c;展现了当前SOTA大语言模型在长上下…