4、pytest -- fixtures:明确的、模块化的和可扩展的

2023-11-20

pytest fixtures的目的是提供一个固定的基线,使测试可以在此基础上可靠地、重复地执行;对比xUnit经典的setup/teardown形式,它在以下方面有了明显的改进:

  • fixture拥有一个明确的名称,通过声明使其能够在函数、类、模块,甚至整个测试会话中被激活使用;
  • fixture以一种模块化的方式实现。因为每一个fixture的名字都能触发一个fixture函数,而这个函数本身又能调用其它的fixture
  • fixture的管理从简单的单元测试扩展到复杂的功能测试,允许通过配置和组件选项参数化fixture和测试用例,或者跨功能、类、模块,甚至整个测试会话复用fixture

此外,pytest继续支持经典的xUnit风格的测试。你可以根据自己的喜好,混合使用两种风格,或者逐渐过渡到新的风格。你也可以从已有的unittest.TestCase或者nose项目中执行测试;

1. fixture:作为形参使用

测试用例可以接收fixture的名字作为入参,其实参是对应的fixture函数的返回值。通过@pytest.fixture装饰器可以注册一个fixture

我们来看一个简单的测试模块,它包含一个fixture和一个使用它的测试用例:

# src/chapter-4/test_smtpsimple.py

import pytest


@pytest.fixture
def smtp_connection():
    import smtplib

    return smtplib.SMTP("smtp.163.com", 25, timeout=5)


def test_ehlo(smtp_connection):
    response, _ = smtp_connection.ehlo()
    assert response == 250
    assert 0  # 为了展示,强制置为失败

这里,test_ehlo有一个形参smtp_connection,和上面定义的fixture函数同名;

执行:

$ pipenv run pytest -q src/chapter-4/test_smtpsimple.py 
F                                                                 [100%]
=============================== FAILURES ================================
_______________________________ test_ehlo _______________________________

smtp_connection = <smtplib.SMTP object at 0x105992d68>

    def test_ehlo(smtp_connection):
        response, _ = smtp_connection.ehlo()
        assert response == 250
>       assert 0  # 为了展示,强制置为失败
E       assert 0

src/chapter-4/test_smtpsimple.py:35: AssertionError
1 failed in 0.17s

执行的过程如下:

  • pytest收集到测试用例test_ehlo,其有一个形参smtp_connectionpytest查找到一个同名的已经注册的fixture
  • 执行smtp_connection()创建一个smtp_connection实例<smtplib.SMTP object at 0x105992d68>作为test_ehlo的实参;
  • 执行test_ehlo(<smtplib.SMTP object at 0x105992d68>)

如果你不小心拼写出错,或者调用了一个未注册的fixture,你会得到一个fixture <...> not found的错误,并告诉你目前所有可用的fixture,如下:

$ pipenv run pytest -q src/chapter-4/test_smtpsimple.py 
E                                                                 [100%]
================================ ERRORS =================================
______________________ ERROR at setup of test_ehlo ______________________
file /Users/yaomeng/Private/Projects/pytest-chinese-doc/src/chapter-4/test_smtpsimple.py, line 32
  def test_ehlo(smtp_connectio):
E       fixture 'smtp_connectio' not found
>       available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, smtp_connection, smtp_connection_package, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
>       use 'pytest --fixtures [testpath]' for help on them.

/Users/yaomeng/Private/Projects/pytest-chinese-doc/src/chapter-4/test_smtpsimple.py:32
1 error in 0.02s

注意:

你也可以使用如下调用方式:

pytest --fixtures [testpath]

它会帮助你显示所有可用的 fixture;

但是,对于_开头的fixture,需要加上-v选项;

2. fixture:一个典型的依赖注入的实践

fixture允许测试用例可以轻松的接收和处理特定的需要预初始化操作的应用对象,而不用过分关心导入/设置/清理的细节;这是一个典型的依赖注入的实践,其中,fixture扮演者注入者(injector)的角色,而测试用例扮演者消费者(client)的角色;

以上一章的例子来说明:test_ehlo测试用例需要一个smtp_connection的连接对象来做测试,它只关心这个连接是否有效和可达,并不关心它的创建过程。smtp_connectiontest_ehlo来说,就是一个需要预初始化操作的应用对象,而这个预处理操作是在fixture中完成的;简而言之,test_ehlo说:“我需要一个SMTP连接对象。”,然后,pytest就给了它一个,就这么简单。

关于依赖注入的解释,可以看看Stackflow上这个问题的高票回答如何向一个5岁的孩子解释依赖注入?

When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.

What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.

更详细的资料可以看看维基百科Dependency injection

3. conftest.py:共享fixture实例

如果你想在多个测试模块中共享同一个fixture实例,那么你可以把这个fixture移动到conftest.py文件中。在测试模块中你不需要手动的导入它,pytest会自动发现,fixture的查找的顺序是:测试类、测试模块、conftest.py、最后是内置和第三方的插件;

你还可以利用conftest.py文件的这个特性为每个目录实现一个本地化的插件

4. 共享测试数据

如果你想多个测试共享同样的测试数据文件,我们有两个好方法实现这个:

  • 把这些数据加载到fixture中,测试中再使用这些fixture
  • 把这些数据文件放到tests文件夹中,一些第三方的插件能帮助你管理这方面的测试,例如:pytest-datadirpytest-datafiles

5. 作用域:在跨类的、模块的或整个测试会话的用例中,共享fixture实例

需要使用到网络接入的fixture往往依赖于网络的连通性,并且创建过程一般都非常耗时;

我们来扩展一下上述示例(src/chapter-4/test_smtpsimple.py):在@pytest.fixture装饰器中添加scope='module'参数,使每个测试模块只调用一次smtp_connection(默认每个用例都会调用一次),这样模块中的所有测试用例将会共享同一个fixture实例;其中,scope参数可能的值都有:function(默认值)、classmodulepackagesession

首先,我们把smtp_connection()提取到conftest.py文件中:

# src/chapter-4/conftest.py


import pytest
import smtplib


@pytest.fixture(scope='module')
def smtp_connection():
  return smtplib.SMTP("smtp.163.com", 25, timeout=5)

然后,在相同的目录下,新建一个测试模块test_module.py,将smtp_connection作为形参传入每个测试用例,它们共享同一个smtp_connection()的返回值:

# src/chapter-4/test_module.py


def test_ehlo(smtp_connection):
    response, _ = smtp_connection.ehlo()
    assert response == 250
    smtp_connection.extra_attr = 'test'
    assert 0  # 为了展示,强制置为失败


def test_noop(smtp_connection):
    response, _ = smtp_connection.noop()
    assert response == 250
    assert smtp_connection.extra_attr == 0  # 为了展示,强制置为失败

最后,让我们来执行这个测试模块:

pipenv run pytest -q src/chapter-4/test_module.py 
FF                                                                [100%]
=============================== FAILURES ================================
_______________________________ test_ehlo _______________________________

smtp_connection = <smtplib.SMTP object at 0x107193c50>

    def test_ehlo(smtp_connection):
        response, _ = smtp_connection.ehlo()
        assert response == 250
        smtp_connection.extra_attr = 'test'
>       assert 0  # 为了展示,强制置为失败
E       assert 0

src/chapter-4/test_module.py:27: AssertionError
_______________________________ test_noop _______________________________

smtp_connection = <smtplib.SMTP object at 0x107193c50>

    def test_noop(smtp_connection):
        response, _ = smtp_connection.noop()
        assert response == 250
>       assert smtp_connection.extra_attr == 0
E       AssertionError: assert 'test' == 0
E        +  where 'test' = <smtplib.SMTP object at 0x107193c50>.extra_attr

src/chapter-4/test_module.py:33: AssertionError
2 failed in 0.72s

可以看到:

  • 两个测试用例使用的smtp_connection实例都是<smtplib.SMTP object at 0x107193c50>,说明smtp_connection只被调用了一次;
  • 在前一个用例test_ehlo中修改smtp_connection实例(上述例子中,为smtp_connection添加extra_attr属性),也会反映到test_noop用例中;

如果你期望拥有一个会话级别作用域的fixture,可以简单的将其声明为:

@pytest.fixture(scope='session')
def smtp_connection():
  return smtplib.SMTP("smtp.163.com", 25, timeout=5)

注意:

pytest每次只缓存一个fixture实例,当使用参数化的fixture时,pytest可能会在声明的作用域内多次调用这个fixture

5.1. package作用域(实验性的)

在 pytest 3.7 的版本中,正式引入了package作用域。

package作用域的fixture会作用于包内的每一个测试用例:

首先,我们在src/chapter-4目录下创建如下的组织:

chapter-4/
└── package_expr
    ├── __init__.py
    ├── test_module1.py
    └── test_module2.py

然后,在src/chapter-4/conftest.py中声明一个package作用域的fixture

@pytest.fixture(scope='package')
def smtp_connection_package():
    return smtplib.SMTP("smtp.163.com", 25, timeout=5)

接着,在src/chapter-4/package_expr/test_module1.py中添加如下测试用例:

def test_ehlo_in_module1(smtp_connection_package):
    response, _ = smtp_connection_package
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

4、pytest -- fixtures:明确的、模块化的和可扩展的 的相关文章

  • matplotlib:调整图形窗口大小而不缩放图形内容

    当您调整图形大小时 Matplotlib 会自动缩放图形窗口中的所有内容 通常这是用户想要的 但我经常想增加窗口的大小 为其他东西腾出更多空间 在这种情况下 我希望在更改窗口大小时预先存在的内容保持相同的大小 有谁知道一个干净的方法来做到这
  • 测试交互式Python程序

    我想知道python的哪些测试工具支持交互式程序的测试 例如 我有一个由以下人员启动的应用程序 python dummy program py gt gt Hi whats your name Joseph 我想要仪器Joseph所以我可以
  • 无法使用 Python 循环分页 API 响应

    所以 我对这个感到摸不着头脑 使用 HubSpot 的 API 我需要获取我客户的 门户 帐户 中所有公司的列表 遗憾的是 标准 API 调用一次只能返回 100 家公司 当它返回响应时 它包含两个参数 使分页响应成为可能 其中之一是 ha
  • 类型错误:translate() 只接受一个参数(给定 2 个参数)[重复]

    这个问题在这里已经有答案了 我的代码在 python 2 x 版本上运行良好 但是当我尝试在 python 3 x 版本上运行它时 出现错误 主题 需要缩写短信编码中的任何消息 Code def sms encoding data star
  • 在Python中清理属于不同语言的文本

    我有一个文本集合 其中的句子要么完全是英语 印地语或马拉地语 每个句子附加的 id 为 0 1 2 分别代表文本的语言 无论任何语言的文本都可能有 HTML 标签 标点符号等 我可以使用下面的代码清理英语句子 import HTMLPars
  • 如何在每次运行 python 程序时添加新列

    我希望我的表的第一列作为卷号 第二列作为名称 每当我运行 python 程序时 我想在表中添加一列日期 在这个新列中 我想填充从 user list 获得的列表将包含值 P A P P 等 如何处理 我尝试首先通过 alter 命令添加一列
  • 为什么在 __init__ 函数中声明描述符类会破坏描述符功能?

    在下面的 B 类中 我想要 set 每当您赋值给 A 类中的函数时 就会调用该函数B a 相反 将值设置为B a覆盖B a与价值 C类分配给C a工作正常 但我想为每个用户类都有一个单独的 A 实例 即我不想在 C 的一个实例中更改 a 来
  • 检查列表是否已排序的 Pythonic 方法

    有没有一种Python式的方法来检查列表是否已经排序ASC or DESC listtimestamps 1 2 3 5 6 7 就像是isttimestamps isSorted 返回True or False 我想输入一些消息的时间戳列
  • Python 在 64 位 vista 上获取 os.environ["ProgramFiles"] 的错误值

    Vista64 计算机上的 Python 2 4 3 环境中有以下2个变量 ProgramFiles C Program Files ProgramFiles x86 C Program Files x86 但是当我运行以下命令时 impo
  • 如何使用 numpy 从一维数组创建对角矩阵?

    我正在使用 Python 和 numpy 来做线性代数 我表演了numpy对矩阵进行 SVD 以获得矩阵 U i 和 V 然而 i 矩阵表示为 1 行的 1x4 矩阵 IE 12 22151125 4 92815942 2 06380839
  • 如何在python中访问矩阵每个元素的相邻单元格?

    这里 如果两个单元共享边界 则它们被认为是相邻的 例如 A 5 6 4 2 1 3 7 9 8 这里 索引 0 0 的相邻元素位于索引 0 1 和 1 0 处 索引 1 1 的相邻元素位于索引 0 1 1 0 2 1 处 和 1 2 假设你
  • 如何在自定义 django 命令中抽象出命令代码

    我正在我的应用程序下编写自定义 django 命令management commands目录 目前我在该目录中有 6 个不同的文件 每个文件都有不同的命令来解决独特的需求 然而 有一些实用程序是它们所共有的 抽象出这些公共代码的最佳方法是什
  • 如何使用 Python 实现并行 gzip 压缩?

    使用python压缩大文件 https stackoverflow com questions 9518705 big file compression with python给出了一个很好的例子来说明如何使用例如bz2 纯粹用 Pytho
  • 获取 python 模块的 2 个独立实例

    我正在与以非 OO 方式编写的 python 2 x API 进行交互 它使用模块全局范围来处理一些内部状态驱动的东西 在它不再是单例的情况下需要它 并且修改原始代码 不是我们的 不是一个选择 如果不使用单独解释器的子进程运行 有什么方法可
  • 向结构化 numpy 数组添加字段

    将字段添加到结构化 numpy 数组的最简洁方法是什么 是否可以破坏性地完成 或者是否有必要创建一个新数组并复制现有字段 每个字段的内容是否连续存储在内存中 以便可以有效地完成此类复制 如果您使用 numpy 1 3 还有 numpy li
  • Django INSTALLED_APPS 的命名约定是如何工作的?

    该网站上的教程创建了一个名为 polls 的应用程序 它使用 django 1 9 所以在 INSTALLED APPS 中它是 polls apps PollsConfig 我正在观看一个教程 他将应用程序命名为新闻通讯 并且在 INST
  • datetime strftime 不输出正确的时间戳

    下列 gt gt gt from dateutil parser import parse gt gt gt parse 2013 07 02 00 00 00 0000 datetime datetime 2013 7 2 0 0 tzi
  • python:xml.etree.ElementTree,删除“命名空间”

    我喜欢 ElementTree 解析 xml 的方式 特别是 Xpath 功能 我有一个带有嵌套标签的应用程序的 xml 输出 我想按名称访问此标签而不指定名称空间 这可能吗 例如 root findall molpro job 代替 ro
  • 如何正确将 tflite_graph.pb 转换为 detector.tflite

    我正在使用tensorflow对象检测API使用tensorflow中的ssdlite mobilenet v2 coco 2018 05 09来训练自定义模型模型动物园 https github com tensorflow models
  • “yield item”与 return iter(items) 相比有何优点?

    在下面的示例中 resp results 是一个迭代器 版本1 items for result in resp results item process result items append item return iter items

随机推荐

  • mysql中的default_详解MySQL中default的使用

    详解MySQL中default的使用 发布时间 2020 10 03 17 50 29 来源 脚本之家 阅读 60 作者 子不语 wj NULL 和 NOT NULL 修饰符 DEFAULT 修饰符 AUTO INCREMENT 修饰符 N
  • unity的LOD组件

    本文转载自http blog csdn net huutu article details 52106468 LOD是Level Of Detais 的简称 多细节层次 在游戏场景中 根据摄像机与模型的距离 来决定显示哪一个模型 一般距离近
  • 电脑开机时按F几重装系统

    常使用电脑的朋友都清楚 电脑系统有时候会出现故障 如果是出现不能开机的情况就需重我们装系统 那么如果 重装系统f几进入呢 下面小编现在来为大家详细的介绍一下电脑重装系统开机按F几 一起往下看 工具 原料 系统版本 win7系统 品牌型号 联
  • linux内核学习(7)粗略走走kbuild Makefile编译流程

    今天看Makefile文件 我头大了 此Makefile非彼Makefile 里面多了很多内置命令 比如origin patsubst等等啦 这些都没听说过 更可恶的是 连网上都没有 可见 这是一件多么伤人的事情 分析这样的 真是让人折寿啊
  • Toad常用快捷键和缩写替换

    Toad常用快捷键 F8 调出以前执行的sql命令 F9 执行全部sql Ctrl T 补全table name 或者显示字段 alt 箭头上下 看sql history Ctrl Enter 直接执行当前选中的sql Ctrl Shift
  • 文件服务器恢复测试,基于文件传输中文件损坏检测和恢复办法.doc

    基于文件传输中文件损坏检测和恢复办法 基于文件传输中文件损坏检测和恢复办法 摘 要 在网络上文件传输是一种常见的应用 讨论在文件传输完成后检测错误和恢复数据的办法 关键词 文件传输 文件校验 恢复 中图分类号 TP3 文献标识码 A 文章编
  • Python3学习笔记之-第三方模块(Pillow)

    目录 前言 一 安装Pillow 二 操作图像 前言 在 pillow之前处理图形的库莫过于PIL 但是它支持到python2 7 年久失修 于是一群志愿者在PIL的基础上常见了pillow 支持python3 又丰富和功能特性 一 安装P
  • 百度会员租赁地址

    http xinjipin com 转载于 https www cnblogs com byfboke p 11602017 html
  • 10:00面试,10:04就出来了 ,问的实在是太...

    从外包出来 没想到竟然死在了另一家厂子 自从加入这家公司 每天都在加班 钱倒是给的不少 所以我也就忍了 没想到12月一纸通知 所有人都不许加班 薪资直降30 顿时有吃不起饭的赶脚 好在有个兄弟内推我去了一家互联网公司 兴冲冲见面试官 没想到
  • Maven搭建私有仓库(私服)

    Nexus简介 作为一个非常优秀且我找不到合适的替代品的二进制包储存库 功能也是非常强大 不单纯只能设置Maven私有仓库 包括我们常见的Yum Docker npm NuGel等等 专业版需要付费 个人用免费版就可以 专业版更加强大 专业
  • Communications link failure官网解释

    官网给的解释 https dev mysql com doc connector j 8 0 en connector j usagenotes troubleshooting html qandaitem 15 1 8 15 8 What
  • Ubuntu下QT程序打包(直接拷贝动态库和可执行文件)

    系统为Ubuntu16 04LTS QT版本为5 12 9 QT默认为动态编译 生成的可执行文件需要有依赖库才能运行 因此在打包的时候需要把程序的依赖库一块打包 这样子做会导致打包的程序非常大 因为依赖库也都一块拷贝了 这种方法好处是快捷
  • TS的类型转换

    TS的类型转换 元组类型转联合类型 元组类型转联合类型2 联合类型转交叉类型 将这个方法拆成两部分来看 U extends any k U gt void never 是第一部分 extends k infer I gt void I ne
  • 数据库——数据库备份与恢复

    目录 原因 数据库的备份与恢复 1 使用MySQLdump命令备份 2 恢复数据库 表的导入和导出 1 表的导出 2 表的导入 原因 尽管采取了一些管理措施来保证数据库的安全 但是不确定的意外情况总是有可能造成数据的损失 例 如意外的停电
  • GooglePlay提审警告(com.google.android.gms:play-services-safetynet:17.0.0)

    1 Goole在今年6月份出的新政策 不在使用safetynet 而使用Play Integrity API 2 项目本身没有使用过safetynet 3 使用了firebase 查阅资料 解决方案如下 implementation pla
  • [python]bokeh学习总结——QuickStart

    bokeh是python中一款基于网页的画图工具库 画出的图像以html格式保存 一个简单的例子 from bokeh plotting import figure output file show output file patch ht
  • 电子信息工程电子信息毕设分享100例(一)

    单片机毕业设计项目分享系列 这里是DD学长 单片机毕业设计及享100例系列的第一篇 目的是分享高质量的毕设作品给大家 包含全面内容 源码 原理图 PCB 实物演示 论文 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的单片机项目缺少
  • STM32之音频数据的Flash读取与DAC播放

    文章目录 一 STM32103之内部Flash原理 1 Flash介绍 2 Flash的组成 3 STM32内部框架图 二 SD卡的读写 1 实验过程 2 查看hello txt 3 从SD卡里读出数据 三 Flash地址空间的数据读取 1
  • 说说ERP软件的系统设计--开源软件诞生8

    赤龙ERP系统设计篇 第8篇 用日志记录 开源软件 的诞生 赤龙 ERP 开源地址 点亮星标 感谢支持 与开发者交流 kzca2000 码云 https gitee com redragon redragon erp GitHub http
  • 4、pytest -- fixtures:明确的、模块化的和可扩展的

    pytest fixtures的目的是提供一个固定的基线 使测试可以在此基础上可靠地 重复地执行 对比xUnit经典的setup teardown形式 它在以下方面有了明显的改进 fixture拥有一个明确的名称 通过声明使其能够在函数 类