pytest解讀fixtures之Teardown處理yield和addfinalizer方案
前言
當我們運行測試函數(shù)時,我們希望確保測試函數(shù)在運行結(jié)束后,可以自己清理掉對環(huán)境的影響。這樣的話,它們就不會干擾任何其他的測試函數(shù),更不會日積月累的留下越來越多的測試數(shù)據(jù)。
用過unittest的朋友相信都知道teardown這個函數(shù),做的是一樣的事情,那么下面姑且就把這種“善后”工作的代碼叫做teardown代碼吧。
而pytest中的fixture,也提供了這樣一個非常有用的系統(tǒng),我們可以在里面定義teardown代碼。
這里可以使用2種方式來實現(xiàn),分別是yield
和addfinalizer
一、yield fixtures(推薦)
1, yield 和 return
在有yield
的fixtures函數(shù)中,關(guān)鍵字yield
可以代替 return
,可以把fixture里的一些對象傳遞給調(diào)用它們的fixture函數(shù)或者測試函數(shù)。
就像其他普通的fixture函數(shù)一樣。區(qū)別僅僅是:
yield
替換掉了return
- teardown代碼放置在
yield
之后
2, yield的執(zhí)行順序
pytest在執(zhí)行fixture函數(shù)時,會根據(jù)fixture函數(shù)之間的線性關(guān)系順序調(diào)用的。但是,當測試函數(shù)運行結(jié)束的時候,pytest又會按照之前的順序反方向來執(zhí)行fixture中yield之后的代碼。
結(jié)合示例看下,這里沒有引用官方示例了,手寫一個直觀些的:
import pytest @pytest.fixture def fixture_one(): print("\n執(zhí)行fixture_one") return 1 @pytest.fixture def fixture_two(fixture_one): print("\n執(zhí)行fixture_two") yield 2 print("\n執(zhí)行fixture_two的teardown代碼") @pytest.fixture def fixture_adding(fixture_one, fixture_two): print("\n執(zhí)行fixture_adding") result = fixture_one + fixture_two yield result print("\n執(zhí)行fixture_adding的teardown代碼") def test_demo(fixture_two, fixture_adding): print("\n執(zhí)行測試函數(shù)test_demo") assert fixture_adding == 3
代碼中,fixture中調(diào)用多個fixture,測試函數(shù)中調(diào)用多個fixture,通過前面幾章的接觸,相信大家這時候已經(jīng)可以梳理出前后調(diào)用順序了:
- test_demo 測試函數(shù),先去調(diào)用fixture函數(shù) fixture_two,然后調(diào)用 fixture_adding。
- 在fixture函數(shù) fixture_two中,又會去調(diào)用另一個fixture函數(shù) fixture_one。
- 在fixture函數(shù) fixture_adding中,調(diào)用了 fixture_one、fixture_two。
所以,fixture函數(shù)的先后順序是:fixture_one
、fixture_two
、fixture_adding
。那么,可以得知測試結(jié)束后的teardown代碼執(zhí)行順序:fixture_adding
、fixture_two
。
運行一下代碼,驗證下結(jié)果是否符合我們的梳理:
============================= test session starts ============================= platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: D:\練習\demo_fixture plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 1 item test_module.py 執(zhí)行fixture_one 執(zhí)行fixture_two 執(zhí)行fixture_adding . 執(zhí)行測試函數(shù)test_demo 執(zhí)行fixture_adding的teardown代碼 執(zhí)行fixture_two的teardown代碼 [100%] ============================== 1 passed in 0.09s ==============================
結(jié)果與我們剛才梳理的一致。
但是,值得注意的是,就算是teardown的代碼是按照正確的順序執(zhí)行,也不能保證代碼能正常執(zhí)行的。比如說teardown里的某些代碼執(zhí)行異常了,導致別的清理動作也沒法執(zhí)行。這里就涉及到另一個點了:健壯的fixture結(jié)構(gòu)應該是什么樣子。這個官方文檔另起進行說明,這里同樣。
二、addfinalizer
1.request.addfinalizer把函數(shù)變成終結(jié)器
在pytest中想要做teardown的處理,除了使用帶有yield的fixture函數(shù),還可以直接添加終結(jié)器。直接來看示例代碼:
import pytest @pytest.fixture() def demo_fixture(request): print("\n這個fixture在每個case前執(zhí)行一次") def demo_finalizer(): print("\n在每個case完成后執(zhí)行的teardown") #注冊demo_finalizer為終結(jié)函數(shù) request.addfinalizer(demo_finalizer) def test_01(demo_fixture): print("\n===執(zhí)行了case: test_01===") def test_02(demo_fixture): print("\n===執(zhí)行了case: test_02===")
看下運行結(jié)果:
============================= test session starts ============================= platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: D:\練習\demo_fixture plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 2 items test_module.py 這個fixture在每個case前執(zhí)行一次 . ===執(zhí)行了case: test_01=== 在每個case完成后執(zhí)行的teardown 這個fixture在每個case前執(zhí)行一次 . ===執(zhí)行了case: test_02=== 在每個case完成后執(zhí)行的teardown [100%] ============================== 2 passed in 0.10s ============================== Process finished with exit code 0
運行結(jié)果可以看出,效果與yield是一致的。這算是一個固定寫法,關(guān)于request
文檔中也有另外的講解,屆時再分享。
2.request.addfinalizer注冊多個終結(jié)器函數(shù)
上方代碼是一個終結(jié)函數(shù),如果要注冊多個呢?
import pytest @pytest.fixture() def demo_fixture(request): print("\n這個fixture在每個case前執(zhí)行一次") def demo_finalizer(): print("\n在每個case完成后執(zhí)行的teardown") def demo_finalizer2(): print("\n在每個case完成后執(zhí)行的teardown2") #注冊demo_finalizer為終結(jié)函數(shù) request.addfinalizer(demo_finalizer) request.addfinalizer(demo_finalizer2) def test_01(demo_fixture): print("\n===執(zhí)行了case: test_01===") def test_02(demo_fixture): print("\n===執(zhí)行了case: test_02===") if __name__ == '__main__': pytest.main(['-s', 'test_module.py'])
運行結(jié)果:
============================= test session starts ============================= platform win32 -- Python 3.6.8, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: D:\練習\demo_fixture plugins: allure-pytest-2.8.32, celery-4.3.0, Faker-4.14.2, base-url-1.4.2, html-2.1.1, metadata-1.10.0collected 2 items test_module.py 這個fixture在每個case前執(zhí)行一次 . ===執(zhí)行了case: test_01=== 在每個case完成后執(zhí)行的teardown2 在每個case完成后執(zhí)行的teardown 這個fixture在每個case前執(zhí)行一次 . ===執(zhí)行了case: test_02=== 在每個case完成后執(zhí)行的teardown2 在每個case完成后執(zhí)行的teardown [100%] ============================== 2 passed in 0.09s ============================== Process finished with exit code 0
這里要注意的是,多個終結(jié)器的情況下,執(zhí)行的順序是與注冊時候相反的。
3.yield和addfinalizer的區(qū)別
目前從官方文檔中看到的是
We have to be careful though, because pytest will run that finalizer once it’s been added, even if that fixture raises an exception after adding the finalizer.
一旦添加了終結(jié)器,pytest便會執(zhí)行。
但是,當我嘗試在setup代碼中進行拋錯,終結(jié)器的代碼卻并沒有執(zhí)行。
嘗試搜索外網(wǎng)暫時也沒得到有效的幫助,只能在GitHub上向pytest提了issue了,這里算是埋下一個坑,待后續(xù)解決,更多關(guān)于Teardown處理yield addfinalizer的資料請關(guān)注腳本之家其它相關(guān)文章!
- pytest解讀fixtures中yield與addfinalizer區(qū)別
- pytest官方文檔解讀fixtures的調(diào)用方式
- pytest官方文檔解讀fixtures
- pytest官方文檔解讀fixtures的autouse
- pytest解讀一次請求多個fixtures及多次請求
- pytest官方文檔解讀fixtures調(diào)用fixtures及fixture復用性
- pytest解讀fixture有效性及跨文件共享fixtures
- pytest?fixtures函數(shù)及測試函數(shù)的參數(shù)化解讀
- pytest fixtures裝飾器的使用和如何控制用例的執(zhí)行順序
- Pytest中Fixtures的高級用法
相關(guān)文章
python 阿里云oss實現(xiàn)直傳簽名與回調(diào)驗證的示例方法
這篇文章主要介紹了python 阿里云oss實現(xiàn)直傳簽名與回調(diào)驗證,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-03-03淺談python中str字符串和unicode對象字符串的拼接問題
今天小編就為大家分享一篇淺談python中str字符串和unicode對象字符串的拼接問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-12-12解決Python保存文件名太長OSError: [Errno 36] File
這篇文章主要介紹了解決Python保存文件名太長OSError: [Errno 36] File name too lon問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05Python Pygame實戰(zhàn)之實現(xiàn)經(jīng)營類游戲夢想小鎮(zhèn)代碼版
作為一名模擬經(jīng)營類游戲的發(fā)燒友,各種農(nóng)場類、醫(yī)院類、鐵路類的游戲玩兒了很多年。今天用代碼給大家打造一款夢想小鎮(zhèn)游戲,希望大家喜歡啦2022-12-12