python優(yōu)化測試穩(wěn)定性的失敗重試工具pytest-rerunfailures詳解
前言
筆者在執(zhí)行自動化測試用例時,會發(fā)現(xiàn)有時候用例失敗并非代碼問題,而是由于服務(wù)正在發(fā)版,導(dǎo)致請求失敗,從而降低了自動化用例的穩(wěn)定性,最后還要花時間定位到底是自身case
的原因還是業(yè)務(wù)邏輯問題,還是其他原因,增加了定位成本。增加容錯機(jī)制,失敗重試,會解決大部分由于網(wǎng)絡(luò)原因、服務(wù)重啟等原因造成的case
失敗問題。那該如何增加失敗重試機(jī)制呢?帶著問題我們一起探索。
pytest-rerunfailures 插件
先給出答案,我們將使用pytest-rerunfailures
插件來實(shí)現(xiàn)失敗重試功能。
什么是pytest-rerunfailures?
pytest-rerunfailures
是一個基于 pytest 框架的插件,它允許我們對測試用例進(jìn)行失敗重試。當(dāng)一個測試用例失敗時,插件會自動重新運(yùn)行失敗的測試用例,直到達(dá)到預(yù)定的重試次數(shù)或測試用例通過為止。這樣可以增加用例的穩(wěn)定性,并減少因?yàn)榕及l(fā)性問題導(dǎo)致的測試失敗。
如何使用pytest-rerunfailures?
方式一
首先,確保已經(jīng)安裝了 pytest-rerunfailures 插件。可以使用以下命令進(jìn)行安裝:
pip install pytest-rerunfailures
安裝完成后,在項(xiàng)目中使用 pytest 運(yùn)行測試用例時,pytest-rerunfailures 插件會自動生效。
接下來,在編寫測試用例時,可以通過添加 @pytest.mark.flaky
裝飾器將需要重試的測試用例標(biāo)記起來。例如:
test_demo.py
import pytest ? ? @pytest.mark.flaky(reruns=3, reruns_delay=2) def test_case(): ? ?assert 1 == 2 ?
在上述示例中,我們使用了 @pytest.mark.flaky
裝飾器來標(biāo)記測試用例 test_case
為可重試的。參數(shù) reruns
指定了重試次數(shù),而 reruns_delay
則指定了每次重試之間的延遲時間(以秒為單位)。
我們來運(yùn)行case
,看一下執(zhí)行結(jié)果:
執(zhí)行命令:pytest -s -v test_demo.py::test_case
,會看到如下結(jié)果:
RERUN test_dir/test_demo.py::test_case RERUN test_dir/test_demo.py::test_case RERUN test_dir/test_demo.py::test_case FAILED
可以看到,重試了3次,最終結(jié)果為失敗。
注意:如果你是在pycharm中點(diǎn)擊綠色三角形直接運(yùn)行是不生效的
總結(jié)一下:
當(dāng)運(yùn)行測試時,如果測試用例失敗,pytest-rerunfailures 插件會根據(jù)我們配置的重試次數(shù)和延遲時間自動重新運(yùn)行該測試用例,直到達(dá)到最大重試次數(shù)或測試通過為止。
方式二
除了使用裝飾器來標(biāo)記測試用例外,pytest-rerunfailures 還支持使用命令行選項(xiàng)和配置文件的方式進(jìn)行配置。
命令行執(zhí)行的話,可以這樣寫:
pytest -s -v --reruns 3 --reruns-delay 2 test_demo.py::test_case
或者代碼運(yùn)行的話,可以這樣寫:
pytest.main(["-s", "-v", "--reruns", "3", "--reruns-delay", "2", "test_demo.py::test_case"]) ?
運(yùn)行機(jī)制
到這里,應(yīng)該會使用了。我們簡單概括一下它的運(yùn)行機(jī)制:
- pytest 通過插件系統(tǒng)加載 pytest-rerunfailures 插件,并啟用其功能。
- 當(dāng) pytest 運(yùn)行測試時,對每個測試用例的執(zhí)行進(jìn)行監(jiān)控。
- 如果一個測試用例執(zhí)行失敗,pytest-rerunfailures 插件會捕獲該失敗,并判斷是否需要進(jìn)行重試。
- 如果該測試用例被標(biāo)記為可重試(使用了
@pytest.mark.flaky
裝飾器),插件會根據(jù)配置的重試次數(shù)和延遲時間重新運(yùn)行該測試用例。 - 在每次重試之前,插件會根據(jù)設(shè)置的延遲時間暫停一段時間。
- 如果測試用例在重試次數(shù)達(dá)到上限之前通過了,即成功執(zhí)行,則插件會將該測試用例標(biāo)記為通過。
- 如果測試用例在達(dá)到最大重試次數(shù)后仍然失敗,則插件會返回最后一次失敗的結(jié)果作為最終的結(jié)果。
總結(jié)起來,pytest-rerunfailures 插件在測試執(zhí)行失敗時,根據(jù)配置的重試次數(shù)和延遲時間重新運(yùn)行測試用例,并根據(jù)重試結(jié)果判斷最終的測試結(jié)果。這樣可以提高測試用例的穩(wěn)定性,并減少偶發(fā)性問題導(dǎo)致的測試失敗。
源碼解讀
使用階段,我們使用mark
標(biāo)記,那源碼中應(yīng)該添加了該標(biāo)記
def pytest_configure(config): ? ?# add flaky marker ? ?config.addinivalue_line( ? ? ? ?"markers", ? ? ? ?"flaky(reruns=1, reruns_delay=0): mark test to re-run up " ? ? ? ?"to 'reruns' times. Add a delay of 'reruns_delay' seconds " ? ? ? ?"between re-runs.", ? ) ? ?......
簡單解釋一下:
pytest_configure(config)
是 pytest 的一個鉤子函數(shù),用于在 pytest 配置階段對配置進(jìn)行自定義操作。
config.addinivalue_line()
是 pytest 的配置方法,用于向配置中添加新的配置項(xiàng)或配置信息。
- 在這段代碼中,通過
config.addinivalue_line()
方法,插件向 pytest 的配置中加入了一行字符串。
- 這行字符串指定了標(biāo)記名稱為 "flaky",并使用參數(shù)
reruns
和reruns_delay
來說明重試次數(shù)和延遲時間的默認(rèn)值。
- 標(biāo)記的含義是將被標(biāo)記的測試用例重新運(yùn)行最多 "reruns" 次,每次重試之間間隔 "reruns_delay" 秒。
通過這個自定義的標(biāo)記,就可以使用 @pytest.mark.flaky
裝飾器來標(biāo)記需要進(jìn)行重試的測試用例,并且可以在裝飾器中指定具體的重試次數(shù)和延遲時間。
我們看看實(shí)現(xiàn)失敗重試的源碼,這才是重點(diǎn)
def pytest_runtest_protocol(item, nextitem): ? ?""" ? Run the test protocol. ? ? Note: when teardown fails, two reports are generated for the case, one for ? the test case and the other for the teardown error. ? """ ? ?reruns = get_reruns_count(item) ? ?if reruns is None: ? ? ? ?# global setting is not specified, and this test is not marked with ? ? ? ?# flaky ? ? ? ?return ? ? ?# while this doesn't need to be run with every item, it will fail on the ? ?# first item if necessary ? ?check_options(item.session.config) ? ?delay = get_reruns_delay(item) ? ?parallel = not is_master(item.config) ? ?db = item.session.config.failures_db ? ?item.execution_count = db.get_test_failures(item.nodeid) ? ?db.set_test_reruns(item.nodeid, reruns) ? ? ?if item.execution_count > reruns: ? ? ? ?return True ? ? ?need_to_run = True ? ?while need_to_run: ? ? ? ?item.execution_count += 1 ? ? ? ?item.ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location) ? ? ? ?reports = runtestprotocol(item, nextitem=nextitem, log=False) ? ? ? ? ?for report in reports: ?# 3 reports: setup, call, teardown ? ? ? ? ? ?report.rerun = item.execution_count - 1 ? ? ? ? ? ?if _should_not_rerun(item, report, reruns): ? ? ? ? ? ? ? ?# last run or no failure detected, log normally ? ? ? ? ? ? ? ?item.ihook.pytest_runtest_logreport(report=report) ? ? ? ? ? ?else: ? ? ? ? ? ? ? ?# failure detected and reruns not exhausted, since i < reruns ? ? ? ? ? ? ? ?report.outcome = "rerun" ? ? ? ? ? ? ? ?time.sleep(delay) ? ? ? ? ? ? ? ? ?if not parallel or works_with_current_xdist(): ? ? ? ? ? ? ? ? ? ?# will rerun test, log intermediate result ? ? ? ? ? ? ? ? ? ?item.ihook.pytest_runtest_logreport(report=report) ? ? ? ? ? ? ? ? ?# cleanin item's cashed results from any level of setups ? ? ? ? ? ? ? ?_remove_cached_results_from_failed_fixtures(item) ? ? ? ? ? ? ? ?_remove_failed_setup_state_from_session(item) ? ? ? ? ? ? ? ? ?break ?# trigger rerun ? ? ? ?else: ? ? ? ? ? ?need_to_run = False ? ? ? ? ?item.ihook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location) ? ? ?return True
簡單解釋一下:
首先,通過函數(shù) get_reruns_count(item)
獲取當(dāng)前測試用例需要重試的次數(shù)。如果沒有設(shè)置重試次數(shù),則直接返回。
然后,檢查配置選項(xiàng)并獲取重試的延遲時間,并確定是否運(yùn)行在并行模式下。還會獲取失敗記錄數(shù)據(jù)庫對象,并獲取當(dāng)前測試用例已經(jīng)執(zhí)行的次數(shù)。
接下來,通過比較已執(zhí)行次數(shù)和設(shè)定的重試次數(shù),判斷是否需要進(jìn)行重試。如果已執(zhí)行次數(shù)大于等于設(shè)定的重試次數(shù),則不再進(jìn)行重試,直接返回。
如果需要重試,會進(jìn)入一個循環(huán),每次重試會增加已執(zhí)行次數(shù)。在重試過程中,會調(diào)用 pytest_runtest_logstart
函數(shù)記錄測試用例開始執(zhí)行的日志。
然后,通過調(diào)用 runtestprotocol
函數(shù)執(zhí)行測試用例,并獲取測試結(jié)果。在這里,生成的報告會被標(biāo)記為執(zhí)行次數(shù)減一,以便區(qū)分原始執(zhí)行和重試執(zhí)行的報告。
接著,通過 _should_not_rerun
函數(shù)判斷當(dāng)前報告是否滿足不需要重試的條件。如果滿足,則繼續(xù)執(zhí)行后續(xù)操作。
如果報告表明需要重試,并且重試次數(shù)未達(dá)到設(shè)定的次數(shù),會將報告的結(jié)果設(shè)置為 "rerun",并根據(jù)設(shè)定的延遲時間暫停一段時間。
然后,根據(jù)并行模式和當(dāng)前使用的 xdist 版本,決定是否記錄中間結(jié)果。同時,會清除緩存的結(jié)果和執(zhí)行狀態(tài)。
之后,重試循環(huán)會繼續(xù),直到不滿足重試條件為止。最后,會調(diào)用 pytest_runtest_logfinish
函數(shù)記錄測試用例結(jié)束執(zhí)行的日志。
最后,函數(shù)返回 True,表示已經(jīng)實(shí)現(xiàn)重試機(jī)制。
總結(jié)起來,這段代碼通過循環(huán)執(zhí)行測試用例,并在滿足重試條件時進(jìn)行重試,直到滿足退出條件為止。在重試過程中,會記錄日志、生成報告,并根據(jù)設(shè)定的重試次數(shù)和延遲時間進(jìn)行控制。
最后
失敗重試功能并不是解決所有測試問題的法寶,它應(yīng)該被視為一種提高測試穩(wěn)定性的輔助手段。在使用 pytest-rerunfailures 進(jìn)行失敗重試時,我們應(yīng)該仔細(xì)分析失敗的原因,確保重試次數(shù)和延遲時間設(shè)置合理,并與團(tuán)隊成員共同討論和決定是否需要重試測試用例。
總結(jié)起來,pytest-rerunfailures 是一個非常有用的工具,可以提高測試用例的穩(wěn)定性。通過使用它,我們可以輕松地實(shí)現(xiàn)失敗重試功能,并減少由于偶發(fā)性問題導(dǎo)致的測試失敗。
另外源碼中,看到了pytest_runtest_logstart
等,可能有些同學(xué)不明白這是干嘛用的,之后我們專門寫一篇文章來介紹它的作用。
以上就是python優(yōu)化測試穩(wěn)定性的失敗重試工具pytest-rerunfailures詳解的詳細(xì)內(nèi)容,更多關(guān)于python工具pytest-rerunfailures的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在雙python下設(shè)置python3為默認(rèn)的方法
這篇文章主要介紹了如何在雙python下設(shè)置python3為默認(rèn),本文通過一個例子分步驟給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2018-10-10關(guān)于pygame.surface.blit()方法4個參數(shù)的使用
這篇文章主要介紹了關(guān)于pygame.surface.blit()方法4個參數(shù)的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-03-03Python使用Marshmallow輕松實(shí)現(xiàn)序列化和反序列化
這篇文章主要為大家詳細(xì)介紹了Python如何使用Marshmallow輕松實(shí)現(xiàn)序列化和反序列化,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2025-03-03Python 使用 Bert 進(jìn)行中文情感分析的方法
在自然語言處理(NLP)領(lǐng)域,情感分析是一個非常常見且重要的應(yīng)用,本文將帶領(lǐng)新手使用 BERT 模型進(jìn)行中文情感分析,并會詳細(xì)講解如何加載開源數(shù)據(jù)集、訓(xùn)練模型、評估準(zhǔn)確度,并最終導(dǎo)出模型供未來使用,感興趣的朋友跟隨小編一起看看吧2024-10-10在Python 2.7即將停止支持時,我們?yōu)槟銕砹艘环輕ython 3.x遷移指南
這篇文章主要介紹了在Python 2.7即將停止支持時我們?yōu)槟銣?zhǔn)備了一份python 3.x遷移指南的相關(guān)資料,需要的朋友可以參考下2018-01-01Python confluent kafka客戶端配置kerberos認(rèn)證流程詳解
這篇文章主要介紹了Python confluent kafka客戶端配置kerberos認(rèn)證流程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10python實(shí)現(xiàn)超簡單的視頻對象提取功能
這篇文章主要給大家介紹了關(guān)于利用python實(shí)現(xiàn)超簡單的視頻對象提取功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06pytorch中tensor.expand()和tensor.expand_as()函數(shù)詳解
今天小編就為大家分享一篇pytorch中tensor.expand()和tensor.expand_as()函數(shù)詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12