32
社区成员




首先看下如下例子,test_demo.py内容如下:
import pytest
@pytest.fixture(autouse=True,scope="function")
def function_fixture():
print("\nin function_fixture setup ...")
a=1/0
yield 10
print("\nin function_fixture teardown ...")
def test_func3(function_fixture):
print("in test_func3...")
assert function_fixture == 11
执行结果如下,仔细观察就会发现,当在setup部分出错了,则teardown部分根本就不会执行了,这一点对于自动化测试来讲是有一定弊端的,比如在setup部分配置了一些基础数据,然后由于某种原因出错了,这样由于根本不会执行teardown的操作,从而导致整体环境就有残留了,这就是yield关键字存在的弊端
$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: D:\src\blog\tests, configfile: pytest.ini
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 1 item
test_demo.py
in function_fixture setup ...
E
================================================================================ ERRORS ================================================================================
_____________________________________________________________________ ERROR at setup of test_func3 _____________________________________________________________________
@pytest.fixture(autouse=True,scope="function")
def function_fixture():
print("\nin function_fixture setup ...")
> a=1/0
E ZeroDivisionError: division by zero
test_demo.py:6: ZeroDivisionError
======================================================================= short test summary info ========================================================================
ERROR test_demo.py::test_func3 - ZeroDivisionError: division by zero
=========================================================================== 1 error in 0.10s ===========================================================================
如下,通过request的addfinalizer则可以解决这个问题
test_demo.py内容如下:
import pytest
@pytest.fixture(autouse=True,scope="function")
def function_fixture(request):
def teardown_op():
print("\nin function_fixture teardown ...")
request.addfinalizer(teardown_op)
print("\nin function_fixture setup ...")
a=10/0
return 10
def test_func3(function_fixture):
print("in test_func3...")
assert function_fixture == 11
执行结果如下,可以发现虽然setup部分虽然出错了,但是teardown仍然可以正常执行
pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: D:\src\blog\tests, configfile: pytest.ini
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 1 item
test_demo.py
in function_fixture setup ...
E
in function_fixture teardown ...
================================================================================ ERRORS ================================================================================
_____________________________________________________________________ ERROR at setup of test_func3 _____________________________________________________________________
request = <SubRequest 'function_fixture' for <Function test_func3>>
@pytest.fixture(autouse=True,scope="function")
def function_fixture(request):
def teardown_op():
print("\nin function_fixture teardown ...")
request.addfinalizer(teardown_op)
print("\nin function_fixture setup ...")
> a=10/0
E ZeroDivisionError: division by zero
test_demo.py:10: ZeroDivisionError
======================================================================= short test summary info ========================================================================
ERROR test_demo.py::test_func3 - ZeroDivisionError: division by zero
=========================================================================== 1 error in 0.10s ===========================================================================
上面的优化能解决teardown不执行的问题,但是还有另外的问题,比如setup有5个步骤,teardown有对应的5个步骤,则按照上面的解决办法带来一个问题是比如setup中在第二个步骤中报错了,则此时相当于setup只成功执行了一个步骤,而上述解决方案中的teardown中不得不把5个步骤全部执行,这在一些场景中也是有问题的
为了解决上面的问题,下面的解决方案则可能稍微更好一些,即还是使用yield关键字,不过每一个fixture的setup只做原子操作,teardown也只做与setup对应的原子操作,如下代码中f1,f2,f3中的setup和teardown分别只做原子操作,假设在f2的setup中由于某种原因出错,此时f2因为setup报错了,因此f2没有必要执行teardown,而采用这种方案即使f2中setup失败了,f1的teardown仍然执行,如此则达到了只要setup成功了就会执行其对应的teardown操作
如下test_demo.py代码如下:
import pytest
@pytest.fixture(scope="function")
def f1():
print("\nin f1 fixture setup...")
yield
print("\nin f1 fixture teardown...")
@pytest.fixture(scope="function")
def f2(f1):
print("\nin f2 fixture setup...")
a=1/0
yield
print("\nin f2 fixture teardown...")
@pytest.fixture(scope="function")
def f3(f2):
print("\nin f3 fixture setup...")
yield 10
print("\nin f3 fixture teardown...")
def test_func3(f3):
print("\nin test_func3...")
assert f3 == 11
执行结果如下:
$ pytest -s
========================================================================= test session starts ==========================================================================
platform win32 -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: D:\src\blog\tests, configfile: pytest.ini
plugins: allure-pytest-2.9.43, caterpillar-pytest-0.0.2, hypothesis-6.31.6, forked-1.3.0, rerunfailures-10.1, xdist-2.3.0
collected 1 item
test_demo.py
in f1 fixture setup...
in f2 fixture setup...
E
in f1 fixture teardown...
================================================================================ ERRORS ================================================================================
_____________________________________________________________________ ERROR at setup of test_func3 _____________________________________________________________________
f1 = None
@pytest.fixture(scope="function")
def f2(f1):
print("\nin f2 fixture setup...")
> a=1/0
E ZeroDivisionError: division by zero
test_demo.py:12: ZeroDivisionError
======================================================================= short test summary info ========================================================================
ERROR test_demo.py::test_func3 - ZeroDivisionError: division by zero
=========================================================================== 1 error in 0.10s ===========================================================================