在之前介紹pytest中的fixture用法的文章中https://zhuanlan.zhihu.com/p/87775743,提到了teardown的實現。
最近在翻pytest官方文檔的時候,又發現了addfinalizer這個函數,跟yield一樣,也可以實現在case結束后運行關鍵字之后的代碼。那今天就來捋一下這2者的用法和區別。
一、yield
再來簡單回顧下pytest里的setUp和tearDown的用法,我們可以看到,下方代碼里有三個case用例,分別是test_開頭。
而在demo_fixture函數里,有一個yield關鍵字。那么在yield之前的代碼,會在case之前執行,yield之后的代碼,則會在case運行結束后執行。
#yield_finalizer_demo.py
import pytest
@pytest.fixture()
def demo_fixture():
print("\n這個fixture在每個case前執行一次")
yield
print("\n在每個case完成后執行的teardown")
def test_01(demo_fixture):
print("\n===執行了case: test_01===")
def test_02(demo_fixture):
print("\n===執行了case: test_02===")
def test_03(demo_fixture):
print("\n===執行了case: test_03===")
好了,現在我3個case都傳入這個demo_fixture,運行一下,看下效果。這3個紅色框中標出的分別就是每一個case執行前后的代碼輸出,符合我們的預期。
二、addfinalizer
現在,我們再來看addfinalizer,這里我姑且叫它終結器。在用法上,addfinalizer跟yield是不同的,需要你去注冊作為終結器使用的函數。
這里還是用上方的代碼去修改,去掉yield關鍵字,增加一個新的函數demo_finalizer,並且注冊成終結函數:
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===")
def test_03(demo_fixture):
print("\n===執行了case: test_03===")
接下來,運行一下,可以看到結果與使用yield的時候一致。
三、yield與addfinalizer的區別
那么,除了在使用上的區別之外,yield與addfinalizer還有什么不同呢?
1. 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")
def demo_finalizer3():
print("\n在每個case完成后執行的teardown3")
#注冊demo_finalizer為終結函數
request.addfinalizer(demo_finalizer)
request.addfinalizer(demo_finalizer2)
request.addfinalizer(demo_finalizer3)
def test_01(demo_fixture):
print("\n===執行了case: test_01===")
def test_02(demo_fixture):
print("\n===執行了case: test_02===")
def test_03(demo_fixture):
print("\n===執行了case: test_03===")
在代碼里增加demo_finalizer2,demo_finalizer3,這2個終結函數。運行一下:
可以看到,注冊的3個函數都被執行了,但是要注意的是執行順序,與注冊的順序相反。
2. 當setUp的代碼執行錯誤,addfinalizer依舊會執行
這里接官方文檔上的例子說明一下:
@pytest.fixture
def equipments(request):
r = []
for port in ('C1', 'C3', 'C28'):
equip = connect(port)
request.addfinalizer(equip.disconnect)
r.append(equip)
return r
比如,C1,C3,C28這3個端口連接,如果C28這個端口失敗了,這時候會拋出一個連接異常,但是在執行teardown關閉連接的時候,C1和C3的依然可以正常關閉。