4、Fixture的相互調用 示例: import pytest # 第一層fixture @pytest.fixture() def fixture_1(): data = "fixture_1" print("這是第一層fixture") return data # 第二層fixture @py ...
目錄
4、Fixture的相互調用
示例:
import pytest
# 第一層fixture
@pytest.fixture()
def fixture_1():
data = "fixture_1"
print("這是第一層fixture")
return data
# 第二層fixture
@pytest.fixture()
def fixture_2(fixture_1): # 在這裡傳遞調用第一層fixture
print("這是第二層fixture")
# 第三層fixture
@pytest.fixture()
@pytest.mark.usefixtures("fixture_1") # 這種fixture相互調用方式不生效
def fixture_3():
print("這是第三層fixture")
# 測試類
class TestClass:
def test_1(self, fixture_1):
print("調用第1層fixture,返回值為{}".format(fixture_1))
def test_2(self, fixture_2):
print("調用第2層fixture,返回值為{}".format(fixture_2))
def test_3(self, fixture_3):
print("調用第3層fixture")
"""
執行結果
fixture/use_fixture_each_other.py::TestClass::test_1 這是第一層fixture
調用第1層fixture,返回值為fixture_1
PASSED
fixture/use_fixture_each_other.py::TestClass::test_2 這是第一層fixture
這是第二層fixture
調用第2層fixture,返回值為None
PASSED
fixture/use_fixture_each_other.py::TestClass::test_3 這是第三層fixture
調用第3層fixture
PASSED
"""
示例說明:
- 在調用存在相互調用的
fixture
時,執行順序由頂層fixture
逐層向下執行(如示例test_2
優先執行fixture_1
再執行fixture_2
) - 當調用存在相互調用的
fixture
時,直接被調用的fixture
不會將自己接收到的返回值返回給調用方(如示例test_2
不會接收到由fixture_1
返回的值) - 相互調用
fixture
時不能使用pytest.mark.usefixture
裝飾器(如示例fixture_3
)
5、Fixture復用
不同的測試函數可以請求相同的fixture
,每個測試函數都會獲得該fixture的各自結果。不同的測試函數不互相影響,這樣可以保證每個測試函數都能得到乾凈一致的數據。
示例
import pytest
@pytest.fixture()
def fixture_1():
return []
def test_1(fixture_1):
fixture_1.append(0)
print(f"結果:{fixture_1}")
def test_2(fixture_1):
fixture_1.append(9)
print(f"結果:{fixture_1}")
"""
執行結果
fixture/reuse_fixture.py::test_1 結果:[0]
PASSED
fixture/reuse_fixture.py::test_2 結果:[9]
PASSED
"""
示例說明
由上面例子可以看出,兩個測試函數都調用了fixture_1
,但每次調用返回的結果是一樣的,並不會因為test_1
中fixture_1
先添加了0而影響test_2
調用的fixture_1
返回的結果
6、Fixture緩存返回結果
在同一個測試函數多次調用同一個fixture
時,第一次執行該fixture
函數之後,會把返回結果緩存起來,不會再次執行它們
示例:
import pytest
@pytest.fixture()
def fixture_1():
print("執行fixture_1")
return "a"
@pytest.fixture()
def fixture_2():
print("執行fixture_2")
return []
@pytest.fixture()
def fixture_append(fixture_1, fixture_2):
print("執行fixture_append")
fixture_2.append(fixture_1)
def test_fixture(fixture_append, fixture_2, fixture_1):
print("執行測試函數")
print(fixture_2)
"""
執行結果
fixture/fixture_cache.py::test_fixture 執行fixture_1
執行fixture_2
執行fixture_append
執行測試函數
['a']
PASSED
"""
示例說明:
由上面例子可以看出在fixture
函數fixture_append
中,fixture_1
第一次被請求返回字母a
,fixture_2
被第二次被請求返回空列表,在測試函數test_fixture
中fixture_2
第二次被請求,但返回結果不是不是空列表,而是['a']
。如果同一個fixture
在同一個測試函數中每次都去請求,那麼必然返回的是空列表。
7、Fixture的後置處理
前面的案例都是加了前置處理,相當於setup()
,後置teardown()
在fixture
中是可以通過yield
關鍵字和addfinalizer
關鍵字來實現
(一)使用yield關鍵字實現後置
- 示例
import pytest
@pytest.fixture(autouse=True)
def fixture_3():
print("這是一個前置處理")
yield
print("這是一個後置處理")
def testcase_1(fixture_3):
print("這是測試用例1")
def testcase_2(fixture_3):
print("這是測試用例2")
"""
執行結果
fixture/use_fixture_3.py::testcase_1 這是一個前置處理
這是測試用例1
PASSED這是一個後置處理
fixture/use_fixture_3.py::testcase_2 這是一個前置處理
這是測試用例2
PASSED這是一個後置處理
"""
- 執行順序
在前置處理中會根據fixture函數之間的線性關係順序調用的,後置處理順序會反過來
import pytest
@pytest.fixture()
def fixture_1():
print("這是fixture_1")
return 1
@pytest.fixture()
def fixture_2(fixture_1):
print("這是fixture_2的【前置】")
yield 2
print("這是fixture_2的【後置】")
@pytest.fixture()
def fixture_add(fixture_1, fixture_2):
print("這是fixture_add的【前置】")
yield fixture_1 + fixture_2
print('這是fixture_add的【後置】')
def test_fixture(fixture_2, fixture_add):
print("這是測試函數")
assert fixture_add == 3
"""
執行結果
fixture/yiled_order.py::test_fixture 這是fixture_1
這是fixture_2的【前置】
這是fixture_add的【前置】
這是測試函數
PASSED這是fixture_add的【後置】
這是fixture_2的【後置】
"""
(二)使用addfinalizer關鍵字實現後置
- request.addfinalizer把函數變成終結器實現後置處理
import pytest
@pytest.fixture()
def fixture_1(request):
print("這是fixture_1的【前置】處理")
def addfinalizer_demo():
print("這是fixture_1的【後置】處理")
# 註冊後置處理
request.addfinalizer(addfinalizer_demo)
def test_fixture(fixture_1):
print("===這是測試函數===")
"""
執行結果
fixture/use_addfinalizer.py::test_fixture 這是fixture_1的【前置】處理
===這是測試函數===
PASSED這是fixture_1的【後置】處理
"""
- request.addfinalizer註冊多個終結器函數
import pytest
@pytest.fixture()
def fixture_1(request):
print("這是fixture_1的【前置】處理")
def addfinalizer_demo_1():
print("這是fixture_1的【後置】處理1")
def addfinalizer_demo_2():
print("這是fixture_2的【後置】處理2")
# 將多個後置處理函數註冊成終結函數
request.addfinalizer(addfinalizer_demo_1)
request.addfinalizer(addfinalizer_demo_2)
def test_fixture(fixture_1):
print("=====這是測試函數=====")
"""
執行結果
fixture/use_more_addfinalizer.py::test_fixture 這是fixture_1的【前置】處理
=====這是測試函數=====
PASSED這是fixture_2的【後置】處理2
這是fixture_1的【後置】處理1
"""
- 執行順序
由上面註冊多個終結器函數示例中可以看到,使用addfinalizer
關鍵字處理後置函數的執行順序與註冊順序是反的
(三)yield和addfinalizer的區別
區別在於如果fixture
中前置出現異常,yield
後置不會執行,而addfinalizer
後置會執行。
- 使用
yield
import pytest
@pytest.fixture()
def fixture_yield():
print("這是fixture_yield前置")
res = 21/0
yield
print("這是fixtue_yield後置")
def test_fixture(fixture_yield):
print("這是測試函數")
"""
執行結果
yield_error.py::test_fixture ERROR [100%]這是fixture_yield前置
test setup failed
@pytest.fixture()
def fixture_yield():
print("這是fixture_yield前置")
> res = 21/0
E ZeroDivisionError: division by zero
yield_error.py:12: ZeroDivisionError
"""
- 使用
addfinalizer
import pytest
@pytest.fixture()
def fixture_1(request):
print("這是fixture_1前置")
def addfinalizer_demo():
print("這是fixture_1後置")
request.addfinalizer(addfinalizer_demo)
res = 21/0
def test_fixture(fixture_1):
print("這是測試函數")
"""
執行結果
addfinalizer_error.py::test_fixture ERROR [100%]這是fixture_1前置
test setup failed
request = <SubRequest 'fixture_1' for <Function test_fixture>>
@pytest.fixture()
def fixture_1(request):
print("這是fixture_1前置")
def addfinalizer_demo():
print("這是fixture_1後置")
request.addfinalizer(addfinalizer_demo)
> res = 21/0
E ZeroDivisionError: division by zero
addfinalizer_error.py:16: ZeroDivisionError
這是fixture_1後置
"""
從上面yield
和addfinalizer
的示例中可以看出yield
前置中出現異常,後置處理沒有被執行,而addfinalizer
的前置中出現異常,並沒有影響後置的執行。
註意: 使用addfinalizer
一定是後置函數註冊成功後出現異常才不會受影響。