pytest-教程-14-fixture之yield关键字

领取资料,咨询答疑,请➕wei:  June__Go

上一小节我们学习了pytest conftest.py文件的使用方法,本小节我们讲解一下fixture的yield关键字实现teardown后置操作。

当我们运行我们的测试时,我们会希望确保它们自己清理干净,这样它们就不会与任何其他测试混淆(同时我们也不会留下大量的测试数据来使系统膨胀)。pytest中的 Fixtures 提供了一个非常有用的拆卸系统,它允许我们定义每个 Fixture 自行清理所需的特定步骤。分别是通过yield或addfinalizer完成teardown清理,下面分别对这两种方式进行展开说明。

yield方式完成清理(推荐)

使用yield的fixture和普通的fixture基本差不多,但还是有以下两点:

  • return改换成yield。
  • 需要做清理的代码写在yield的下面。

使用yield后,fixture的执行顺序是这样的,如有两个fixture函数,fixture1和fixture2,先由pytest计算出fixture的线性顺序,它将运行每个fxiture直到它返回,然后移动到列表中的下一个夹具做同样的事情。等待测试完成后,pytest将返回到fxiture列表,但顺序相反,如果开始先执行了fixture1再执行了fixture2,那么后面就是先执行fixture2在执行fixture1.

示例:

test_demo.py

import pytest@pytest.fixture
def get_token():print("\n请求获取token\n")yield# 这里写你的清理代码print("\n注销token\n")def test_demo(get_token):print("测试用例")

运行结果:

============================= test session starts =============================
collecting ... collected 1 itemtest_demo.py::test_demo 
请求获取tokenPASSED                                           [100%]测试用例注销token============================== 1 passed in 0.02s ==============================

注:通过结果展示,我们可以清楚的看到我们的清理代码在测试用例运行过后运行了。这种方式比我们用setup和teardown要好很多,可以抽取公共代码,减少代码冗余。

多个yield的fixture执行顺序

test_demo.py

import pytest@pytest.fixture
def fn1():print("\n我是fn1,我在yield前面\n")yield 1print("\n我是fn1,我在yield后面\n")@pytest.fixture
def fn2(fn1):print("\n我是fn2,我在yield前面\n")yield 2print("\n我是fn2,我在yield后面\n")def test_demo(fn2):print("\n我是测试用例\n")

运行结果:

============================= test session starts =============================
collecting ... collected 1 itemtest_demo.py::test_demo 
我是fn1,我在yield前面我是fn2,我在yield前面PASSED                                           [100%]
我是测试用例我是fn2,我在yield后面我是fn1,我在yield后面============================== 1 passed in 0.02s ==============================

注:通过上述例子,我们可以很明显知道yield的fixture的执行顺序,pytest先计算出线性顺序,先执行了fn1,然后再执行了fn2,再执行test,清理时就先执行的fn2,然后再执行fn1,与开始的顺序相反。

yield遇到异常

1、如果其中一个用例在执行时出现异常,不影响yield后面的teardown执行,运行结果互不影响,并且全部用例执行完之后,yield唤起teardown操作。

test_demo.py

import pytest@pytest.fixture(scope="module")
def open():print("打开浏览器,并且打开百度首页")yieldprint("执行teardown!")print("最后关闭浏览器")def test_s1(open):print("用例1:搜索python-1")# 如果第一个用例异常了,不影响其他的用例执行raise NameError  # 模拟异常def test_s2(open):print("用例2:搜索python-2")def test_s3(open):print("用例3:搜索python-3")if __name__ == "__main__":pytest.main(["-s", "test_f1.py"])

运行结果:

============================= test session starts =============================
collecting ... collected 3 itemstest_demo.py::test_s1 打开浏览器,并且打开百度首页
FAILED                                             [ 33%]用例1:搜索python-1test_demo.py:11 (test_s1)
open = Nonedef test_s1(open):print("用例1:搜索python-1")# 如果第一个用例异常了,不影响其他的用例执行
>       raise NameError  # 模拟异常
E       NameErrortest_demo.py:16: NameErrortest_demo.py::test_s2 PASSED                                             [ 66%]用例2:搜索python-2test_demo.py::test_s3 PASSED                                             [100%]用例3:搜索python-3
执行teardown!
最后关闭浏览器========================= 1 failed, 2 passed in 0.24s =========================

2、但是fixture函数如果在setup执行期间发生异常,那么pytest是不会去执行yield后面的teardown内容。

test_demo.py

import pytest@pytest.fixture(scope="module")
def open():10 / 0print("打开浏览器,并且打开百度首页")yieldprint("执行teardown!")print("最后关闭浏览器")def test_s1(open):print("用例1:搜索python-1")# 如果第一个用例异常了,不影响其他的用例执行raise NameError  # 模拟异常def test_s2(open):print("用例2:搜索python-2")def test_s3(open):print("用例3:搜索python-3")if __name__ == "__main__":pytest.main(["-s", "test_f1.py"])

运行结果:

============================= test session starts =============================
collecting ... collected 3 itemstest_demo.py::test_s1 ERROR                                              [ 33%]
test setup failed
@pytest.fixture(scope="module")def open():
>       10 / 0
E       ZeroDivisionError: division by zerotest_demo.py:6: ZeroDivisionErrortest_demo.py::test_s2 ERROR                                              [ 66%]
test setup failed
@pytest.fixture(scope="module")def open():
>       10 / 0
E       ZeroDivisionError: division by zerotest_demo.py:6: ZeroDivisionErrortest_demo.py::test_s3 ERROR                                              [100%]
test setup failed
@pytest.fixture(scope="module")def open():
>       10 / 0
E       ZeroDivisionError: division by zerotest_demo.py:6: ZeroDivisionError============================== 3 errors in 0.27s ==============================

yield关键字+with上下文管理器的结合使用

yield 关键字 也可以配合 with 上下文管理器 语句使用。【使得代码更加精简】

示例

import pytest
import smtplib@pytest.fixture(scope="module")
def smtp_connection():with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:yield smtp_connection

使用addfinalizer方法完成清理

除了yield可以实现teardown,我们也可以通过 request.addfinalizer() 的方式去注册终结函数来实现 teardown 用例的后置操作。addfinalizer 的用法跟 yield 是不同的, addfinalizer 需要你去注册一个或多个作为终结器使用的函数。

例如:增加一个函数 fin,并且注册成终结函数。

test_demo.py

import pytest@pytest.fixture(scope="module")
def test_addfinalizer(request):# 前置操作setupprint("\n===打开浏览器===\n")test = "test_addfinalizer"def fin():# 后置操作teardownprint("\n===关闭浏览器===\n")request.addfinalizer(fin)# 返回前置操作的变量return testdef test_case(test_addfinalizer):print("===最新用例===", test_addfinalizer)

运行结果:

============================= test session starts =============================
collecting ... collected 1 itemtest_demo.py::test_case 
===打开浏览器===PASSED                                           [100%]===最新用例=== test_addfinalizer===关闭浏览器================================= 1 passed in 0.02s ==============================

yield 与 addfinalizer 用法的区别

① addfinalizer 可以注册多个终结函数。当注册多个终结函数时,用例的后置操作同时会执行完所有的终结函数。

【注意】终结函数(用例后置操作函数)的执行顺序与其在fixture函数中注册的顺序相反(即先注册的终结函数后执行,后注册的终结函数先执行)

示例:

import pytest@pytest.fixture()
def demo_addfinalizer(request):print("====setup====")def fin1():print("====teardown1====")def fin2():print("====teardown2====")def fin3():print("====teardown3====")# 注册fin1、fin2、fin3为终结函数request.addfinalizer(fin1)request.addfinalizer(fin2)request.addfinalizer(fin3)def test_case1(demo_addfinalizer):print("====执行用例test_case1====")def test_case2(demo_addfinalizer):print("====执行用例test_case2====")def test_case3(demo_addfinalizer):print("====执行用例test_case3====")if __name__ == '__main__':pytest.main(__file__, '-s')

运行结果:

============================= test session starts =============================
collecting ... collected 3 itemstest_demo.py::test_case1 ====setup====
PASSED                                          [ 33%]====执行用例test_case1====
====teardown3====
====teardown2====
====teardown1====test_demo.py::test_case2 ====setup====
PASSED                                          [ 66%]====执行用例test_case2====
====teardown3====
====teardown2====
====teardown1====test_demo.py::test_case3 ====setup====
PASSED                                          [100%]====执行用例test_case3====
====teardown3====
====teardown2====
====teardown1================================== 3 passed in 0.03s ==============================

②当执行测试用例时setup前置操作函数的代码执行错误或者发生异常时,addfinalizer 注册的终结函数依旧会执行。

③ yield 关键字可以返回setup前置操作函数中生成的测试数据,且 yield 关键字返回测试数据之后后续的代码依然可以运行。且后续执行的代码充当teardown后置操作函数。

④ addfinalizer 函数可以将一个或者多个函数注册为终结函数(一个或多个函数必须在fixture函数中定义),此时的终结函数为teardown后置操作函数;且最后可以使用 return 关键字返回setup前置操作函数生成的测试数据

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走,希望可以帮助到大家!领取资料,咨询答疑,请➕wei:  June__Go

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

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

相关文章

STM32标准库——(17)硬件SPI读写W25Q64

1.SPI外设简介 时钟频率就是sck波形的频率,一个sck时钟交换一个bit,所以时钟频率一般体现的是传输速度,单位是Hz或者bit/s,那这里的时钟频率是fPCLK除以一个分频系数,分频系数可以配置为2或4或8、16、32、64、128、256…

C++核心编程之内存分区模型,引用,函数提高

1,类型分区模型 c程序在执行中,将内存大方向划分为4个区域 1,代码区:存放函数体的二进制代码,由操作系统进行管理的 2,全局区:存放全局变量和静态变量以及常量 3,栈区&#xff1…

基于SSM的学科竞赛管理系统。Javaee项目。ssm项目。

演示视频: 基于SSM的学科竞赛管理系统。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring SpringMvcMybatisVueLayuiElemen…

MP2494图纸 国产替代型号SC72001宽工作输入电压范围:4.5V 至 80V

MP2494 是一款单片降压开关变换器。它在宽输入范围内可实现 2A 连续输出电流,具有出色的负载和线性调整率。其控制良好的开关沿降低了 EMI 干扰。故障保护功能包括逐周期限流保护和过温关断保护。MP2494 最大限度地减少了现有标准外部元器件的使用。MP2494采用SOIC8…

win系统如何同时安装MySQL5和MySQL8

win系统如何同时安装MySQL5和MySQL8 文章目录 win系统如何同时安装MySQL5和MySQL81、准备好两种版本的数据库2、下载后解压到你指定的目录3、手动配置安装MySQL5和8安装MySQL53.1创建my.ini文件3.2生成data文件夹 安装MySQL83.1创建my.ini文件3.2生成data文件夹 4、配置环境变量…

面试高频率问答题目

索引: 主键索引:表的id (唯一 且 不能为空) 唯一索引:表User 假设有account 字段 ,用户名不重复 (唯一 可以为空) 复合索引:where() 的条件 用户名,密码 …

计算机组成原理----数据的表示和运算

一:进位计数制 1、进制 B:二进制:0-1 逢二进一、借一当二 O:八进制:0-7 逢八进一 D:十进制:0-9 逢十进一 H:十六进制:0-9、A-F 逢十六进一 r进制2 2、…

Cohere

文章目录 关于 cohere公司介绍目标:构建大模型基础设施产品商业模式 API 使用基于 Cohere AI 实现语义搜索 关于 cohere PYPI : https://pypi.org/project/cohere官网 : https://cohere.comgithub : https://github.com/cohere-ai/cohere-python文档:ht…

【2024】vue-router和pinia的配置使用

目录 vue-routerpiniavue-routerpinia进阶用法---动态路由 有同学在项目初始化后没有下载vue-router和pinia,下面开始: vue-router npm install vue-router然后在src目录下创建文件夹router,以及下面的index.ts文件: 写进下面的…

python--产品篇--游戏-坦克

文章目录 准备代码main.pycfg.py 效果 准备 下载 代码 main.py import os import cfg import pygame from modules import *主函数 def main(cfg):# 游戏初始化pygame.init()pygame.mixer.init()screen pygame.display.set_mode((cfg.WIDTH, cfg.HEIGHT))pygame.display.…

CHI协议学习

原始文档:https://developer.arm.com/documentation/102407/0100/?langen CHI 总线拓扑结构 CHI总线拓扑是实现自定义的,可以是RING/MESH/CROSSBAR的类型; RING 一般适用于中等规模芯片MESH 一般适用于大规模芯片CROSSBAR 一般适用于小规模…

工具函数模板题(蓝桥杯 C++ 代码 注解)

目录 一、Vector容器: 二、Queue队列 三、Map映射 四、题目(快递分拣 vector): 代码: 五、题目(CLZ银行问题 queue): 代码: 六、题目(费里的语言 map&…