上一篇讲到fixture通过scope参数控制前置setup的范围,既然有setup作为用例之前前的操作,用例执行完之后那肯定也有teardown操作。
使用fixture的teardown操作并不需要独立的函数,用yield关键字可实现teardown操作
#使用yield关键字实现teardown_xxx的功能
import pytest
# 此时,login函数是一个测试固件,相当于实现了setup_xxx&teardown_xxx的功能。
@pytest.fixture()
def login():
############# 以下的代码相当于setup部分 ###########
print('登录系统')
token = 'a1b23c'
yield token
############# 以下的代码相当于teardown部分 ###########
print('退出登录')
# 在测试函数里, 通过形参声明要使用的测试固件
def test1(login):
# login参数的值是测试固件函数的返回值
print('执行测试 test1: ', login)
print('测试1')
def test2(login):
print('执行测试 test2: ', login)
print('测试2')
# 通过python解释器执行需要以下代码
if __name__ == '__main__':
pytest.main(["-s", "test_yieldDemo.py"])
执行结果:
"C:\Program Files\Python37\python.exe" E:/PycharmProjects/api_pytest/testsfixture/test_yieldDemo.py
============================= test session starts =============================
platform win32 -- Python 3.7.1, pytest-6.1.1, py-1.9.0, pluggy-0.13.1
rootdir: E:\PycharmProjects\api_pytest, configfile: pytest.ini
plugins: allure-pytest-2.8.18
collected 2 items
test_yieldDemo.py 登录系统
执行测试 test1: a1b23c
测试1
.退出登录
登录系统
执行测试 test2: a1b23c
测试2
.退出登录
============================== 2 passed in 0.08s ==============================
Process finished with exit code 0
说明:yield
yield
在fixture
中起到了唤起teardown
的作用,同时也可以和return
一样返回值。
但yield
和return
的区别是:return
执行完成,该函数终止;yield
在返回结束后,后续的代码仍可执行。
import pytest
@pytest.fixture(scope="module")
def open():
print("打开浏览器,并且打开百度首页")
yield
print("执行teardown!")
print("最后关闭浏览器")
def test_s1(open):
print("用例1:搜索python-1")
def test_s2(open):
print("用例2:搜索python-2")
def test_s3(open):
print("用例3:搜索python-3")
if __name__ == "__main__":
pytest.main(["-s", "test_fixturemodule2.py"])
执行结果:
test_fixturemodule2.py 打开浏览器,并且打开百度首页
用例1:搜索python-1
.用例2:搜索python-2
.用例3:搜索python-3
.执行teardown!
最后关闭浏览器
request.addfinalizer()注册清理函数
1.除了yield可以实现teardown,我们也可以通过request.addfinalizer()的方式实现“teardown”。它和yield相比不同的是:无论是固件的“setup”部分是否出现异常或断言失败,它都会执行(关于这一点我还没有演示出来,感觉setup中如果有异常addfinalizer依然不会执行,希望大佬指导);此外它还支持传入多个函数。
#上例子:我们在固件中传入request参数;又在固件中定义了一个内置函数;最后将定义的内置函数添加到request的addfinalizer中。
import pytest
# login函数是一个测试固件,相当于实现了setup_xxx&teardown_xxx的功能
@pytest.fixture()
# 声明使用request测试固件
def login(request):
print('登录系统')
token = 'a1b23c'
# 定义一个清理函数, 清理函数向相当于teardown_xxx
#assert 1 == 2
def fin():
print('退出登录')
assert 1==2 #teardown部分报异常也不影响,request.addfinalizer(fin)还是会执行这个函数
# 注册一个清理函数
request.addfinalizer(fin)
# 注册完清理函数后,如果在测试固件里抛出异常,清理函数照常执行
return token
#@pytest.mark.xfail()
def test_1(login):
print('in test1: ', login)
print('测试1')
#@pytest.mark.xfail()
def test_2(login):
print('in test2: ', login)
print('测试2')
if __name__ == "__main__":
pytest.main(["-s", "test_addfinalizer.py"])
执行结果:
"C:\Program Files\Python37\python.exe" E:/PycharmProjects/api_pytest/testsfixture/test_addfinalizer.py
============================= test session starts =============================
platform win32 -- Python 3.7.1, pytest-6.1.1, py-1.9.0, pluggy-0.13.1
rootdir: E:\PycharmProjects\api_pytest, configfile: pytest.ini
plugins: allure-pytest-2.8.18
collected 2 items
test_addfinalizer.py 登录系统
in test1: a1b23c
测试1
.退出登录
E登录系统
in test2: a1b23c
测试2
.退出登录
E
=================================== ERRORS ====================================
_________________________ ERROR at teardown of test_1 _________________________
def fin():
print('退出登录')
> assert 1==2 #teardown部分报异常也不影响,request.addfinalizer(fin)还是会执行这个函数
E assert 1 == 2
test_addfinalizer.py:17: AssertionError
_________________________ ERROR at teardown of test_2 _________________________
def fin():
print('退出登录')
> assert 1==2 #teardown部分报异常也不影响,request.addfinalizer(fin)还是会执行这个函数
E assert 1 == 2
test_addfinalizer.py:17: AssertionError
=========================== short test summary info ===========================
ERROR test_addfinalizer.py::test_1 - assert 1 == 2
ERROR test_addfinalizer.py::test_2 - assert 1 == 2
========================= 2 passed, 2 errors in 0.92s =========================
Process finished with exit code 0