Pytest精通指南(12)Parametrize源码拆解


文章目录

      • 前言
      • Parametrize 参数化
      • Parametrize 源码分析
      • Parametrize 使用说明
      • 一个参数的参数化
      • 多个参数的参数化
      • 验证类中有多个测试函数
      • 验证变量或函数传递参数化
      • 验证笛卡尔积
      • 拓展用法


请添加图片描述

前言

pytest 中,有两种常见的参数化方法:

@pytest.mark.parametrize装饰器:

  • @pytest.mark.parametrizepytest中最直接的参数化方法。

    它允许我们为测试函数提供多组输入和期望的输出,这样测试函数就可以使用不同的参数组合多次执行。

Fixture:

  • Fixturepytest 中的一个强大功能,允许我们创建一些可以在多个测试之间共享的设置和清理代码。虽然fixture本身不是用来参数化的,但我们可以使用它们来实现参数化的效果

应用场景:

  • @pytest.mark.parametrize 适用于简单的参数化场景,其中每组参数都是静态的,不需要进行复杂的设置或清理。
  • Fixture实现的参数化 是通过创建多个fixtures来实现的,每个fixture可以包含不同的测试数据或状态。它适用于需要更复杂设置和清理的场景,或者当我们想在不同的测试之间共享相同的设置代码时。

Parametrize 参数化

前文Pytest速查表(08)利用Fixture实现参数化讲解了利用Fixture实现参数化,同学们可以查漏补缺;

本文讲解一下Parametrize参数化,Parametrize也是一个内置标记,在命令行中通过pytest --markers可以看到。

请添加图片描述

Parametrize 源码分析

1.在 pytest 的源码中,_ParametrizeMarkDecorator 类是一个内部类,用于实现 @pytest.mark.parametrize 装饰器的功能。

2.我们看到的 ...Python类型注解中的 Ellipsis 对象,通常用作占位符,表示该参数有默认值,但在这里它可能是用于表示参数的具体实现细节尚未在此处展开。

3.当使用@pytest.mark.parametrize装饰器来装饰一个测试函数时,pytest的内部机制会捕获这个装饰器并处理它;

4.pytest会创建一个_ParametrizeMarkDecorator的实例,并将装饰器参数(如argnames, argvalues等)传递给这个实例;

5.然后,当运行测试时,pytest会识别这个装饰器并调用其__call__方法,以生成多个测试实例,每个实例都有不同的参数集。

6.虽然在这段代码中看不到__call__方法的实际实现(由...表示),但可以假设pytest在内部实现了这个方法,以便处理参数化逻辑。具体来说,__call__方法可能会:

  • 验证argnamesargvalues参数的有效性和兼容性。
  • 根据argnamesargvalues生成多个测试实例。
  • 处理indirect参数,以确定哪些参数应该通过pytest的fixture机制间接提供。
  • 处理ids参数,为每个测试实例生成一个唯一的标识符。
  • 处理scope参数,以确定参数化的作用域。
    class _ParametrizeMarkDecorator(MarkDecorator):def __call__(  # type: ignore[override]self,argnames: Union[str, Sequence[str]],argvalues: Iterable[Union[ParameterSet, Sequence[object], object]],*,indirect: Union[bool, Sequence[str]] = ...,ids: Optional[Union[Iterable[Union[None, str, float, int, bool]],Callable[[Any], Optional[object]],]] = ...,scope: Optional[_ScopeName] = ...,) -> MarkDecorator:...

最终根据__call__方法得出结论,Parametrize方法完整体是:

@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None))

Parametrize实例参数的含义和用途如下:

argnames:

  • 含义: argnames 参数定义了将要传递给测试函数的参数名称。

它可以是一个字符串(表示单个参数名称)或一个字符串序列(表示多个参数名称)。

  • 用途: 这个参数告诉 pytest 在执行测试函数时需要传递哪些参数,以及这些参数的顺序。

argvalues:

  • 含义: argvalues 是一个可迭代对象,它包含了要传递给测试函数的参数值。

这些值应该按照 argnames 中定义的顺序排列。

  • 用途: 这个参数允许我们为 argnames 中定义的每个参数提供一组或多组值,以便多次运行测试函数。

indirect:

  • 含义: indirect 参数是一个布尔值或一个字符串序列。

如果设置为 True,则 argvalues 中的每个值都应被解释为 fixture 名称的字符串,而不是直接的参数值。

如果是一个字符串序列,则它应该与 argnames 中的参数名称相对应,指示哪些参数应该通过 fixture 来间接提供。

  • 用途: 这个参数允许我们指定某些参数值不是直接传递给测试函数的,而是通过 pytestfixture 机制间接提供的。这对于需要复杂设置或共享状态的测试非常有用。

ids:

  • 含义: ids 参数是一个可选参数,它可以是一个可迭代对象或一个可调用对象。

如果是一个可迭代对象,它应该与 argvalues 中的每组参数值相对应,为每个测试实例提供一个唯一的标识符。

如果是一个可调用对象,它应该接收一个参数值并返回一个标识符。

  • 用途: ids 参数允许我们为每组参数值提供一个自定义的标识符,这在生成的测试报告中可以使测试结果更容易区分。

scope:

  • 含义: scope 参数是一个可选参数,它指定了参数化的作用域。

作用域可以是 "session", "class", "function", 或 "module"

  • 用途: 这个参数定义了参数化的生命周期。

例如,如果 scope 设置为 "session",则参数化将在整个测试会话中保持有效,而不是为每个测试函数重新创建。这可以影响参数化值的创建和销毁时间,以及它们在不同测试之间的共享程度。

Parametrize 使用说明

  • @pytest.mark.parametrize装饰器可以用来装饰测试函数、测试方法(类中的方法)和测试类。它的主要目的是为被装饰的测试方法提供多组输入数据和预期的输出数据,以执行多次测试。

  • @pytest.mark.parametrize装饰器应用于一个测试类时,它会为该类下的每个测试方法提供指定的测试数据。这意味着测试类中的所有测试方法都会使用相同的数据集进行多次测试。

  • 在一个测试方法上应用了一个@pytest.mark.parametrize装饰器,并提供了N组数据,那么这个方法将会被调用N次,每次使用一组不同的数据

  • 可以在一个函数或方法上应用多个@pytest.mark.parametrize装饰器,但这样做时,它们会生成笛卡尔积,即每个装饰器分别提供了X、Y、Z组数据,那么这个方法将会被调用X*Y*Z次。(每个argnamesargvalues的组合都会被测试一次)。

    对于测试类,通常不建议在类级别应用多个参数化装饰器,而是在类的方法上分别应用。

一个参数的参数化

示例代码

**注意:**测试方法形参名要和parametrize里面的参数一样

import pytest@pytest.mark.parametrize("data1", [1, 3, 5, 7, 9])
class TestClassDemo1:def test_case_01(self, data1):print(f"data1 = {data1}")

执行结果

请添加图片描述

多个参数的参数化

示例代码

import pytest@pytest.mark.parametrize(argnames="entered,expected",argvalues=[["1+1", 2], ["2*3", 6], ["1-1", 0]])
def test_case_01(entered, expected):print(f"entered={entered}, eval(entered)={eval(entered)}, expected={expected}")assert eval(entered) == expected

执行结果

请添加图片描述

验证类中有多个测试函数

示例代码

import pytest@pytest.mark.parametrize("data1", [1, 3, 5, 7, 9])
class TestClassDemo1:def test_case_01(self, data1):print(f"data1-1 = {data1}")def test_case_02(self, data1):print(f"data1-2 = {data1}")def test_case_03(self, data1):print(f"data1-3 = {data1}")

执行结果

请添加图片描述

验证变量或函数传递参数化

示例代码

import pytestdata = [["1+1", 2], ["2*3", 6], ["1-1", 0]]def get_data():return data# @pytest.mark.parametrize(argnames="entered,expected", argvalues=data)
@pytest.mark.parametrize(argnames="entered,expected", argvalues=get_data())
def test_case_01(entered, expected):print(f"entered={entered}, eval(entered)={eval(entered)}, expected={expected}")assert eval(entered) == expected

执行结果

请添加图片描述

验证笛卡尔积

示例代码

import pytest@pytest.mark.parametrize("username", ["admin", "root", "test"])
@pytest.mark.parametrize("password", ["admin", "root", "test"])
class TestClassDemo4:def test_case_04(self, username, password):print(f"name={username}, technology={password}")# parametrize与fixture混合也会出现笛卡尔积效果
# @pytest.fixture(params=["admin", "root", "test"])
# def username(request):
#     return request.param# @pytest.mark.parametrize("password", ["admin", "root", "test"])
# def test_case(username, password):
#     print(f"name={username}, password={password}")        

执行效果

请添加图片描述

拓展用法

添加pytest.ini配置信息

[pytest]
addopts = -s --strict-markers
markers =mark1mark2mark3

示例代码

import pytest@pytest.mark.parametrize("entered,expected",[("1+1", 2),pytest.param("2*3", 6, marks=[pytest.mark.mark1, pytest.mark.skip], id="test 2*3"),pytest.param("1-1", 0, marks=[pytest.mark.mark2, pytest.mark.xfail], id="test 1-1"),pytest.param("3+7", 10, marks=[pytest.mark.mark1,pytest.mark.skipif(condition=True, reason="Skipping multiplication test")],id="test 3+7"),pytest.param("4/2", 2, marks=pytest.mark.mark3, id="test 4/2")]
)
def test_case_01(entered, expected):print(f"entered={entered}, eval(entered)={eval(entered)}, expected={expected}")assert eval(entered) == expected

执行结果

请添加图片描述

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

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

相关文章

哈希密码破解方法汇总

案例: 如何破译 254aa248acb47dd654ca3ea53f48c2c26 e93a1ec56258df7674c4 258df7674c4 该hash加密串的原文信息 步骤: 1)通过Hash Analyzer - TunnelsUP站点了解该hash加密串所使用的哈希加密算法类型。 可知,使用了 sha2-256 加密算法。 2) 访问example_hashes [hash…

C语言-Linux:简单实现Linux的cp指令

在Linux操作系统中,cp 命令是一种常用的文件和目录复制工具。以下是对cp命令的详细说明,包括其基本语法、常用选项以及一些示例用法: 基本语法: cp [选项] 源 目标 其中: 源:指要复制的文件或目录。目标&am…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之十一 简单给视频添加水印图片效果 一、简单介绍 二、简单给视频添加水印图片效果实现…

【Linux学习】初识Linux指令(二)

文章标题 1.rm 指令2.man指令3.nano指令4.cp指令5.mv指令6.alias指令7. cat与8.echo指令 ⚶文章简介 ⚶本篇文章继上篇文章Linux指令讲解,本篇文章主要会涉及到的指令会有:rm指令与 *(通配符)的搭配使用,man指令&…

[重学Python]Day3 函数和模块的使用

[重学Python]Day3 函数和模块的使用 一、函数的作用二、定义函数三、函数的参数四、用模块管理函数五、练习(一)实现计算最大公约数和最小公倍数的函数(二)、实现判断一个数是不是回文数的函数(三)、实现判…

专业SEO优化指南:设置网站关键词的详细步骤

在网站SEO优化的过程中,关键词的设置是提升网站排名的关键步骤之一。那么,作为一名专业的SEO人员,如何有效地进行关键词设置呢?以下是一些详细的步骤: 1. 确定网站的核心关键词。 这需要深入理解网站的主题或产品。通…

整体性学习

整体性学习的顺序: 1.获取 2.理解(明白)3.拓展(探究)4.纠错(调试)5.应用 测试伴随每一个过程 例如: 吃饭(去学习)–>点菜(学什么&#xff0c…

实时数据同步之Maxwell和Canal

文章目录 一、概述1、实时同步工具概述1.1 Maxwell 概述1.2 Canal概述 2、数据同步工作原理2.1 MySQL 主从复制过程2.2 两种工具工作原理 3、MySQL 的 binlog详解3.1 什么是 binlog3.2 binlog 的开启3.3 binlog 的分类设置 4、Maxwell和Canal对比5、环境安装 二、Maxwell 使用1…

日本极致产品力|一个战略符号打造年销售超4亿份的冰淇淋大单品

日本赤城乳业有一款冰棍——ガリガリ君(GariGarikun),凭借着自己的“纯粹”打入市场,几十年来它成为许多日本人的夏日必备。他让人记忆最深刻的是战略符号——ガリガリ君,让赤城乳业打造出年销售4亿份的冰淇淋大单品。它是如何做到的呢? 石油…

Django——CBV源码解析

Django——CBV源码解析 以下是views模块调用as_view()方法的代码示例 # urls.py from django.contrib import admin from django.urls import path import app.viewsurlpatterns [path(admin/, admin.site.urls),path(app/, app.views.task.as_view()), ]# views.py class t…

Day55 动态规划 part15

Day55 动态规划 part15 392.判断子序列 我的思路: 自己还是只能想到双指针法 解答: class Solution {public boolean isSubsequence(String s, String t) {if(s.length() 0) {return true;}if(s.length() > t.length() || t.length() 0) {return false;}ch…

性能再升级!UNet+注意力机制,新SOTA分割准确率高达99%

UNet结合注意力机制能够有效提升图像分割任务的性能。 具体来说,通过将注意力模块集成到UNet的架构中,动态地重新分配网络的焦点,让其更集中在图像中对于分割任务关键的部分。这样UNet可以更有效地利用其跳跃连接特性,以精细的局…

VMware安装Linux虚拟机(rocky9)

软件准备: VMware虚拟机ISO系统镜像文件 选择创建虚拟机→典型→下一步→点击稍后安装操作系统 选择Linux系统和对应版本 输入虚拟机名称和选择保存位置 设置磁盘大小 根据需要自定义硬件配置→完成 然后点击编辑虚拟机设置→CD/DVD→选择ISO镜像 然后开启虚拟机→…

动态规划|343.整数拆分

力扣题目链接 class Solution { public:int integerBreak(int n) {vector<int> dp(n 1);dp[2] 1;for (int i 3; i < n ; i) {for (int j 1; j < i / 2; j) {dp[i] max(dp[i], max((i - j) * j, dp[i - j] * j));}}return dp[n];} }; 思路 看到这道题目&…

【GD32】 2.39 FR1002人脸识别模块

2.39 FR1002人脸识别模块 FR1002人脸识别模组解决方案以高性能应用处理器为硬件平台&#xff0c;配合双目传感器进行活体检测&#xff0c;具有启动速度快、金融级的识别能力、超低使用功耗等特点。凭借超低功耗、强大的运算速度&#xff0c;在多种应用领域中&#xff0c;为各行…

关于《CS创世 SD NAND》的技术学习分享

最近发现一个好玩的东西《CS创世 SD NAND》&#xff0c;带大家一起体验一下。 本文引用了部分厂家产品资料及图像&#xff0c;如有侵权&#xff0c;请及时联系我删除&#xff0c;谢谢。 《CS创世 SD NAND》官方网站&#xff1a;http://www.longsto.com/ 什么是CS创世 SD NAND呢…

0基础刷图论最短路 1(从ATcoder 0分到1800分)

ATC最短路1 &#xff08;本文难度rated 0~ 1000&#xff09; 题目来源&#xff1a;Atcoder 题目收集&#xff1a; https://atcoder-tags.herokuapp.com/tags/Graph/Shortest-Path &#xff08;里面按tag分类好了Atcoder的所有题目&#xff0c;类似cf&#xff09; &#xff08;…

Linux 关闭交换分区(swap)

安装Doris、ElasticSearch等服务的时候&#xff0c;Linux交换分区会给这些服务带来很严重的性能问题&#xff0c;需要在安装之前禁用交换分区。 1 查看交换分区信息 首先&#xff0c;使用 swapon --show 或 cat /proc/swaps 命令来查看当前的交换分区状态。它会列出所有当前启…

【300套】基于Springboot+Vue的Java实战开发项目(附源码+演示视频+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享300的Java毕业设计&#xff0c;基于Springbootvue框架&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业…

【vue】用vite创建vue项目

前置要求 要有Node.js 1. 用vite创建vue项目 在cmd中&#xff0c;进入一个文件夹 在文件资源管理器上面的文件目录中&#xff0c;输入cmd&#xff0c;回车在cmd中通过cd命令进入对应文件夹 创建项目 npm create vitelatest # 创建项目创建项目过程中的一些选项 Ok to pro…