pytest(7)-yield与终结函数
通过上一篇文章,我们已经知道了pytest
中,可以使用Fixture
来完成运行测试用例之前的一些操作如连接数据库,以及测试执行之后自动去做一些善后工作如清空脏数据、关闭数据库连接等。
我们已经学会了fixture
函数的简单用法,但其实fixture
还提供了两种非常优雅高效的写法,来完成测试执行前的处理操作与执行后的处理操作,即使用yield
或addfinalizer
来实现。
yield
在fixture中的关键字yield主要有两个作用:
yield
代替return
进行参数的传递- 起到代码的分割作用,yield之前的代码为
setup
的作用,yield之后的代码为teardown
的作用
yield 与 return
在 pytest 的fixture
函数中可以使用yield
代替return
进行返回,示例如下:
import pytest
@pytest.fixture(autouse=True)
def fixture_one():
print("执行fixture_one")
yield 1
def test_e(fixture_one):
print("执行test_e")
print(fixture_one)
assert fixture_one == 1
if __name__ == '__main__':
pytest.main(["-s"])
运行结果如下:
test_case_4.py::test_e
执行fixture_one
PASSED [100%]执行test_e
1
============================== 1 passed in 0.12s ==============================
从运行结果我们能看到fixture_one
会返回1
并传递给test_e
,与return
的作用完全一致。但如果仅仅只是这样使用的话,毫无意义,因为使用return
足够了。所以,在实际的使用过程中我们一般会在yield
后面加上teardown
的代码。
yield 与 teardown
yield不进行参数传递
对于不需要在前置操作中返回数据的 fixture 函数,加入yield
,那么yield之前的代码为用例执行之前的操作(即setup),yield之后的代码为用例执行之后的操作(即teardown)。示例如下:
import pytest
@pytest.fixture()
def fixture_demo():
# setup
print("\n连接数据库")
yield
# teardown
print("清空脏数据")
def test_case(fixture_demo):
print("执行test_case")
assert True
if __name__ == '__main__':
pytest.main(["-s"])
运行结果如下:
从结果中我们可以看出来,先执行了setup部分,再执行测试用例,最后执行teardown部分。
yield进行参数传递
yield
可以将参数传递给测试用例。
假设有这样一个场景,需要用到接口1
的返回参数作为接口2
的请求参数,即接口2
依赖接口1
,我们需要写一条测试用例对接口2
进行测试,这个时候可以将接口1
的请求写在前置中,如果是unittest
框架则代码如下:
import unittest
import requests
class TestDemo(unittest.TestCase):
def setup(self):
print("请求接口1")
self.res_1 = requests.get(url=url_1, params=params_1)
def test_api_2(self):
print("验证接口2")
# 将接口1的返回值self.res_1作为请求参数,请求接口2
res = requests.post(url=url_2, data=self.res_1)
# 断言
self.assertEqual(res, "接口2预期的返回结果")
def teardown(self):
print("清空脏数据")
在pytest
框架中使用fixture
+yield
则可编写如下:
@pytest.fixture()
def get_api_1_result():
# setup
res_1 = requests.get(url=url_1, params=params_1)
yield res_1
# teardown
print("清空脏数据")
def test_api_2(get_api_1_result):
print("验证接口2")
# 将接口1的返回值res_1作为请求参数,请求接口2
res = requests.post(url=url_2, data=get_api_1_result)
# 断言
assert res == "接口2预期的返回结果"
其中,fixture 会先通过yield
返回res_1
,并传入测试用例test_api_2
中,test_api_2
运行完成后再去执行yield
后面的代码,即执行print("清空脏数据")
。
通过以上对比unittest
中setup
、teardown
以及参数的传递,我们就能很直观的看出pytest
中yield
的使用方式,此处代码仅为示例。
yield 的执行顺序
有时候我们会遇到一个fixture函数调用另一个或多个fixture函数,且这些函数中可能含有yield,我们先看示例,代码如下:
import pytest
@pytest.fixture
def fixture_1():
print("\n执行fixture_1")
yield 1
print("\n执行fixture_1的teardown代码")
@pytest.fixture
def fixture_2(fixture_1):
print("\n执行fixture_2")
yield 2
print("\n执行fixture_2的teardown代码")
@pytest.fixture
def fixture_add(fixture_1, fixture_2):
print("\n执行fixture_add")
result = fixture_1 + fixture_2
yield result
print("\n执行fixture_add的teardown代码")
def test_demo(fixture_add):
print("\n执行测试函数test_demo")
assert fixture_add == 3
if __name__ == '__main__':
pytest.main(["-s"])
运行结果如下:
rootdir: E:\blog\python接口自动化\apiAutoTest, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1
collecting ... collected 1 item
test_case_4.py::test_demo
执行fixture_1
执行fixture_2
执行fixture_add
PASSED [100%]
执行测试函数test_demo
执行fixture_add的teardown代码
执行fixture_2的teardown代码
执行fixture_1的teardown代码
============================== 1 passed in 0.12s ==============================
从结果可以看出:
test_demo 测试函数执行之前:先执行了 fixture_1,再执行fixture_2,最后执行fixture_add,注意此时都是执行yield之前的的代码;
test_demo 测试函数执行之后:先执行了 fixture_add,再执行fixture_2,最后执行fixture_1,注意此时都是执行yield之后的的代码。
因此,当一个fixture函数调用另一个或多个fixture函数,且fixture函数中含有yield
时,被测试函数调用时有如下执行顺序:
测试函数执行之前,pytest会根据fixture函数之间的线性关系顺序调用,即依次执行
yield
之前的代码。而测试函数执行结束后,pytest会根据之前的顺序反方向执行
fixture
函数中yield
之后的代码。
finalizer
finalizer
即终结器 (终结函数),与unittest中的teardown
作用一样,测试用例执行完成后再执行终结器代码。
在pytest中,fixture除了使用 yield 进行 teardown 之外,还可以使用request.addfinalizer()
定义finalizer
来进行后置操作。
使用addfinalizer
,需要在定义 fixture 函数时传入request
,并以内嵌函数的形式进行定义。终结函数可以定义一个或多个。
定义单个终结函数
示例如下:
import pytest
@pytest.fixture
def fixture_demo(request):
print("\nsetup:每个case开始前执行一次")
# 定义终结函数
def finalizer_demo():
print("\nteardown:每个case完成后执行一次")
# 将finalizer_demo注册为终结函数
request.addfinalizer(finalizer_demo)
def test_2(fixture_demo):
print("\n执行test_2")
def test_1(fixture_demo):
print("\n执行test_1")
if __name__ == '__main__':
pytest.main()
运行结果如下:
rootdir: E:\blog\python接口自动化\apiAutoTest, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1
collecting ... collected 2 items
test_module_02\test_case_3.py::test_2
setup:每个case开始前执行一次
PASSED [ 50%]
执行test_2
teardown:每个case完成后执行一次
test_module_02\test_case_3.py::test_1
setup:每个case开始前执行一次
PASSED [100%]
执行test_1
teardown:每个case完成后执行一次
============================== 2 passed in 0.03s ==============================
从结果可以看出来,在测试用例执行完后会执行addfinalizer
函数,效果与执行yield
后的代码一致。
定义多个终结函数
示例如下:
import pytest
@pytest.fixture
def fixture_demo(request):
print("\nsetup:每个case开始前执行一次")
# 定义终结函数
def finalizer_demo_1():
print("\nteardown1:每个case完成后执行一次")
def finalizer_demo_2():
print("\nteardown2:每个case完成后执行一次")
# 注册为终结函数
request.addfinalizer(finalizer_demo_1)
request.addfinalizer(finalizer_demo_2)
def test_2(fixture_demo):
print("\n执行test_2")
def test_1(fixture_demo):
print("\n执行test_1")
if __name__ == '__main__':
pytest.main()
运行结果如下:
rootdir: E:\blog\python接口自动化\apiAutoTest, configfile: pytest.ini
plugins: html-2.1.1, metadata-1.10.0, ordering-0.6, rerunfailures-9.1.1
collecting ... collected 2 items
test_module_02\test_case_3.py::test_2
setup:每个case开始前执行一次
PASSED [ 50%]
执行test_2
teardown2:每个case完成后执行一次
teardown1:每个case完成后执行一次
test_module_02\test_case_3.py::test_1
setup:每个case开始前执行一次
PASSED [100%]
执行test_1
teardown2:每个case完成后执行一次
teardown1:每个case完成后执行一次
============================== 2 passed in 0.02s ==============================
从结果可以看出,上面示例中测试函数执行完成后,先执行了finalizer_demo_2
,后执行finalizer_demo_1
。
所以, 当有多个终结函数被执行时,执行顺序与注册顺序是相反的。
总结
实际项目中,可以视情况进行选择,但一般情况下,推荐使用yield
,因为这样代码更加简洁高效,且阅读性更强更容易维护。
pytest(7)-yield与终结函数的更多相关文章
- 学习-Pytest(五)yield操作
1.fixture的teardown操作并不是独立的函数,用yield关键字呼唤teardown操作 2.scope="module" 1.fixture参数scope=”modu ...
- yield和send函数
yield作用类似于return,其本质是一个迭代器. 当程序执行到yield时,会结束本次循环,返回一个值,然后内置含有next()函数, 下次在执行时,会从yield结束的地方继续执行. 带yie ...
- pytest 的 yield
前言:1.当 pytest.fixture(scope="module") 时,pytest的yieId 类似unittest的teartownclass 2.当 pytest.f ...
- yield 实现range()函数
def range(*args,step= 1): args = list(args) if len(args) == 2: yield args[0] while args[0]<args[1 ...
- pytest文档6-fixture之yield实现teardown
前言 上一篇讲到fixture通过scope参数控制setup级别,既然有setup作为用例之前前的操作,用例执行完之后那肯定也有teardown操作. 这里用到fixture的teardown操作并 ...
- 《带你装B,带你飞》pytest修仙之路5 - yield操作
1. 简介 上一篇中,我们刚刚实现了在每个用例之前执行初始化操作,那么用例执行完之后如需要清除数据(或还原)操作,可以使用 yield 来实现.fixture通过scope参数控制setup级别,既然 ...
- 【pytest】teardown里的yield和addfinalizer
在之前介绍pytest中的fixture用法的文章中https://zhuanlan.zhihu.com/p/87775743,提到了teardown的实现. 最近在翻pytest官方文档的时候,又发 ...
- 【pytest官方文档】解读fixtures - 7. Teardown处理,yield和addfinalizer
当我们运行测试函数时,我们希望确保测试函数在运行结束后,可以自己清理掉对环境的影响. 这样的话,它们就不会干扰任何其他的测试函数,更不会日积月累的留下越来越多的测试数据. 用过unittest的朋友相 ...
- pytest进阶之fixture函数
fixture函数存在意义 与python自带的unitest测试框架中的setup.teardown类似,pytest提供了fixture函数用以在测试执行前和执行后进行必要的准备和清理工作.但是相 ...
随机推荐
- Tool_Fiddler安装和使用
一.简介 Fiddler(中文名称:小提琴)是一个HTTP的调试代理,以代理服务器的方式,监听系统的Http网络数据流动, Fiddler可以也可以让你检查所有的HTTP通讯,设置断点,以及Fiddl ...
- 您应该知道的35个绝对重要的Linux命令
https://mp.weixin.qq.com/s?__biz=MzU3NTgyODQ1Nw==&mid=2247499293&idx=2&sn=1353b78d6ad01d ...
- centos7-collabora-office(在线文档编辑)
1.wget https://www.collaboraoffice.com/repos/CollaboraOnline/CODE-centos7/repodata/repomd.xml.key &a ...
- 403 Invalid CORS request 跨域问题 invalid+cors+request什么意思
5.跨域问题 跨域:浏览器对于javascript的同源策略的限制 . 以下情况都属于跨域: 跨域原因说明 示例 域名不同 www.jd.com 与 www.taobao.com 域名相同,端口不同 ...
- 《手把手教你》系列技巧篇(五十七)-java+ selenium自动化测试-下载文件-下篇(详细教程)
1.简介 前边几篇文章讲解完如何上传文件,既然有上传,那么就可能会有下载文件.因此宏哥就接着讲解和分享一下:自动化测试下载文件.可能有的小伙伴或者童鞋们会觉得这不是很简单吗,还用你介绍和讲解啊,不说就 ...
- java集合分类
Java中的集合包括三大类,它们是Set.List和Map, Set(集) List(列表) Map(映射) 它们都处于java.util包中,Set.List和Map都是接口,它们有各自的实现类.( ...
- vscode设置vue结构的初始代码片段
{ "Print to console": { "prefix": "vue", "body": [ "< ...
- vscode搜索高亮个性化设置
"workbench.colorCustomizations": { "editor.selectionHighlightBorder": "#1ED ...
- 记一次 .NET 某药品仓储管理系统 卡死分析
一:背景 1. 讲故事 这个月初,有位朋友wx上找到我,说他的api过一段时间后,就会出现只有请求,没有响应的情况,截图如下: 从朋友的描述中看样子程序是被什么东西卡住了,这种卡死的问题解决起来相对简 ...
- actf2020 exec
actf2020 exec 1.根据提示,ping一个127.0.0.1,有回显,ls一下发现index.php 3.方向找错了,绕了一大圈,还cat了index.php也没发现什么 最后没招了,回原 ...