pytest解读fixtures之Teardown处理yield和addfinalizer方案
作者:把苹果咬哭的测试笔记 发布时间:2023-06-18 22:13:01
前言
当我们运行测试函数时,我们希望确保测试函数在运行结束后,可以自己清理掉对环境的影响。这样的话,它们就不会干扰任何其他的测试函数,更不会日积月累的留下越来越多的测试数据。
用过unittest的朋友相信都知道teardown这个函数,做的是一样的事情,那么下面姑且就把这种“善后”工作的代码叫做teardown代码吧。
而pytest中的fixture,也提供了这样一个非常有用的系统,我们可以在里面定义teardown代码。
这里可以使用2种方式来实现,分别是yield
和addfinalizer
一、yield fixtures(推荐)
1, yield 和 return
在有yield
的fixtures函数中,关键字yield
可以代替 return
,可以把fixture里的一些对象传递给调用它们的fixture函数或者测试函数。
就像其他普通的fixture函数一样。区别仅仅是:
yield
替换掉了return
teardown代码放置在
yield
之后
2, yield的执行顺序
pytest在执行fixture函数时,会根据fixture函数之间的线性关系顺序调用的。但是,当测试函数运行结束的时候,pytest又会按照之前的顺序反方向来执行fixture中yield之后的代码。
结合示例看下,这里没有引用官方示例了,手写一个直观些的:
import pytest
@pytest.fixture
def fixture_one():
print("\n执行fixture_one")
return 1
@pytest.fixture
def fixture_two(fixture_one):
print("\n执行fixture_two")
yield 2
print("\n执行fixture_two的teardown代码")
@pytest.fixture
def fixture_adding(fixture_one, fixture_two):
print("\n执行fixture_adding")
result = fixture_one + fixture_two
yield result
print("\n执行fixture_adding的teardown代码")
def test_demo(fixture_two, fixture_adding):
print("\n执行测试函数test_demo")
assert fixture_adding == 3
代码中,fixture中调用多个fixture,测试函数中调用多个fixture,通过前面几章的接触,相信大家这时候已经可以梳理出前后调用顺序了:
test_demo 测试函数,先去调用fixture函数 fixture_two,然后调用 fixture_adding。
在fixture函数 fixture_two中,又会去调用另一个fixture函数 fixture_one。
在fixture函数 fixture_adding中,调用了 fixture_one、fixture_two。
所以,fixture函数的先后顺序是:fixture_one
、fixture_two
、fixture_adding
。那么,可以得知测试结束后的teardown代码执行顺序:fixture_adding
、fixture_two
。
运行一下代码,验证下结果是否符合我们的梳理:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\练习\demo_fixture
plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 1 item
test_module.py
执行fixture_one
执行fixture_two
执行fixture_adding
.
执行测试函数test_demo
执行fixture_adding的teardown代码
执行fixture_two的teardown代码
[100%]
============================== 1 passed in 0.09s ==============================
结果与我们刚才梳理的一致。
但是,值得注意的是,就算是teardown的代码是按照正确的顺序执行,也不能保证代码能正常执行的。比如说teardown里的某些代码执行异常了,导致别的清理动作也没法执行。这里就涉及到另一个点了:健壮的fixture结构应该是什么样子。这个官方文档另起进行说明,这里同样。
二、addfinalizer
1.request.addfinalizer把函数变成终结器
在pytest中想要做teardown的处理,除了使用带有yield的fixture函数,还可以直接添加终结器。直接来看示例代码:
import pytest
@pytest.fixture()
def demo_fixture(request):
print("\n这个fixture在每个case前执行一次")
def demo_finalizer():
print("\n在每个case完成后执行的teardown")
#注册demo_finalizer为终结函数
request.addfinalizer(demo_finalizer)
def test_01(demo_fixture):
print("\n===执行了case: test_01===")
def test_02(demo_fixture):
print("\n===执行了case: test_02===")
看下运行结果:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\练习\demo_fixture
plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 2 items
test_module.py
这个fixture在每个case前执行一次
.
===执行了case: test_01===
在每个case完成后执行的teardown
这个fixture在每个case前执行一次
.
===执行了case: test_02===
在每个case完成后执行的teardown
[100%]
============================== 2 passed in 0.10s ==============================
Process finished with exit code 0
运行结果可以看出,效果与yield是一致的。这算是一个固定写法,关于request
文档中也有另外的讲解,届时再分享。
2.request.addfinalizer注册多个终结器函数
上方代码是一个终结函数,如果要注册多个呢?
import pytest
@pytest.fixture()
def demo_fixture(request):
print("\n这个fixture在每个case前执行一次")
def demo_finalizer():
print("\n在每个case完成后执行的teardown")
def demo_finalizer2():
print("\n在每个case完成后执行的teardown2")
#注册demo_finalizer为终结函数
request.addfinalizer(demo_finalizer)
request.addfinalizer(demo_finalizer2)
def test_01(demo_fixture):
print("\n===执行了case: test_01===")
def test_02(demo_fixture):
print("\n===执行了case: test_02===")
if __name__ == '__main__':
pytest.main(['-s', 'test_module.py'])
运行结果:
============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: D:\练习\demo_fixture
plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 2 items
test_module.py
这个fixture在每个case前执行一次
.
===执行了case: test_01===
在每个case完成后执行的teardown2
在每个case完成后执行的teardown
这个fixture在每个case前执行一次
.
===执行了case: test_02===
在每个case完成后执行的teardown2
在每个case完成后执行的teardown
[100%]
============================== 2 passed in 0.09s ==============================
Process finished with exit code 0
这里要注意的是,多个终结器的情况下,执行的顺序是与注册时候相反的。
3.yield和addfinalizer的区别
目前从官方文档中看到的是
We have to be careful though, because pytest will run that finalizer once it’s been added, even if that fixture raises an exception after adding the finalizer.
一旦添加了终结器,pytest便会执行。
但是,当我尝试在setup代码中进行抛错,终结器的代码却并没有执行。
尝试搜索外网暂时也没得到有效的帮助,只能在GitHub上向pytest提了issue了,这里算是埋下一个坑,待后续解决!
来源:https://www.cnblogs.com/pingguo-softwaretesting/p/14479170.html
猜你喜欢
- 哎~工作忙死了!!!!!!今天在百度老年看到一个手写输入法,颇感新鲜。so把其框下!请不要用在商业用途,学习之用,版权百度所有。看代码!注:
- HTTP应答头概述 Web服务器的HTTP
- 将图片读入到Dom中,并将其存为xml文件1、需要命名空间using System.Text;using System.IO;using S
- “操作入口明确”,就是指产品的任何一个功能都要有明确、合理的入口。“操作入口”,指的是产品内部不同模块之间的转接元素,例如在Web产品中,按
- 如果你的PHP网站换了空间,必定要对Mysql数据库进行转移,一般的转移的方法,是备份再还原,有点繁琐,而且由于数据库版本的不一样会导致数据
- 一、首先从SQLServer中Error讲起,SQL中错误处理有些怪辟 错误级别同是16但结果都不同。select *
- 先按照下面的表结构创建mysql_order_by_test数据表,我们用实例一点一点告诉你,MySQL order by的用法。ORDER
- 初学者可以看看。在的img标签有两个属性分别为alt和title,对于很多初学者而言对这两个属性的正确使用都还抱有迷惑,当然这其中一部分原因
- 注意,下述部分主要与DOUBLE和FLOAT列相关,原因在于浮点数的不准确本质。MySQL使用64位十进制数值的精度执行DECIMAL操作,
- 下面十条内容的标题原本是《10 Lessons for Young Designers》,是John C. Jay给年青设计师们的十条经验教
- 很多时候我们写的程序,会花上一分钟甚至几分钟时间。为了使软件使用者能够耐心的等待程序的执行,我们经常会希望有一个进度条来表示程序执行的状态。
- 列表是Python中最基本的数据结构,列表是最常用的Python数据类型,列表的数据项不需要具有相同的类型。列表中的每个元素都分配一个数字
- 此处收集的是一些夺人心魄的创意广告牌,巧妙的构思十分值得大家观瞻.......超人归来 superman returnsNespressos
- 做一个项目用到Ajax,开始觉得挺好,后来发现一个问题,例如删除一项,恢复之后就不能再接着删除,必须要等一段时间,后来知道是IE缓存的问题。
- 介绍:SQL Server 2008变更数据捕获SQL Server 2008的CDC函数读取激活了CDC的每个表所关联的事务日志来记录系统
- 又一个js加密工具:js混淆,完整源代码如下,有点长呵呵:<HTML><HEAD><TITLE>Cunf
- 将有安全问题的SQL过程删除.比较全面.一切为了安全!删除了调用shell,注册表,COM组件的破坏权限MS SQL SERVER2000使
- 有什么办法可以列出数据视图吗?有,假设当前数据库为flashdays,则我们可用下列代码列出它的数据视图:pubDatabase
- 六、XML展望 任何一项新技术的产生都是有其需求背景的,XML的诞生是在HTML遇到不可克服的困难之后。近年来HTML在许多复杂的Web应用
- 如下图,我们在做图片logo列表的时候通常是用li标签来实现。html:<ul class="logolist&q