裝飾器與出錯重試機制
談到穩(wěn)定性,不得不說的就是“出錯重試”機制了克滴,在自動化測試中,由于環(huán)境一般都是測試環(huán)境优床,經(jīng)常會有各種各種的抽風情況影響測試結(jié)果劝赔,這樣就為測試的穩(wěn)定性帶來了挑戰(zhàn),畢竟誰也不想自己的腳本一天到晚的出各種未知問題羔巢,而往往這種環(huán)境的抽風(通常是前端頁面的響應速度和后端接口的響應速度)帶來的影響是暫時的望忆,可能上一秒失敗了,下一秒你再執(zhí)行又好了竿秆,在這種情況下启摄,如果你有一個出錯重試機制,起碼可以在這種暫時性的影響下讓你的腳本安然無恙幽钢,下面我們具體的說一下做法歉备。
什么是裝飾器?
因為我們的做法依賴裝飾器匪燕,所以在去做之前蕾羊,先簡單介紹一下裝飾器。
裝飾器帽驯,表現(xiàn)形式為龟再,在方法(或者類)的上面加上@xxx這樣的語句,假如我們已經(jīng)實現(xiàn)了一個裝飾器名叫retry尼变,那么我們想用它就這么用:
@retry
deftest_login():
print("test")
error=1/0
如果retry實現(xiàn)了出錯再次重試(稍后再說如何實現(xiàn))利凑,那么這么使用的話,就會讓test_login這個case在執(zhí)行出錯的時候再次執(zhí)行。
很神奇哀澈,讓我們來看看實現(xiàn)retry的代碼:
defretry(func):
defwarp():
fortimeinrange(3):
try:
func()
except:
pass
returnwarp
就結(jié)果而言牌借,執(zhí)行以下代碼:
@retry
deftest_login():
print("test")
error=1/0
test_login()
和執(zhí)行:
retry(test_login)()
是等價的,由此我們可以看出割按,裝飾器其實本質(zhì)上就是一個函數(shù)膨报,這個函數(shù)接收其他函數(shù)(或者類)作為參數(shù),通過對這個函數(shù)(或者類)的調(diào)用或者修改适荣,完成不更改原始函數(shù)而修改該函數(shù)的功能现柠。
在這里還有一個知識點,你有沒有想過束凑,在retry內(nèi)部的函數(shù)warp()晒旅,是怎么拿到func這個參數(shù)來執(zhí)行的栅盲?執(zhí)行retry函數(shù)return的是warp這個函數(shù)汪诉,而warp并沒有接受func這個傳參啊。
這就是python里的閉包的概念谈秫,閉包就是指運行時自帶上下文的函數(shù)扒寄,比如這里的warp這個函數(shù),他運行的時候自帶了上層函數(shù)retry傳給他的func這個函數(shù)拟烫,所以才可以在運行時對func進行處理和輸出该编。
了解了裝飾器和閉包,那么下面就很容易做到對測試用例的出錯重試機制了硕淑。
編寫一個出錯重試裝飾器
現(xiàn)在课竣,我們來嘗試自己編寫一個用于測試用例的出錯重試裝飾器,代碼如下:
defretry(times=3,wait_time=10):
defwarp_func(func):
deffild_retry(*args,**kwargs):
fortimeinrange(times):
try:
func(*args,**kwargs)
return
except:
time.sleep(wait_time)
returnfild_retry
returnwarp_func
這個裝飾器可以通過傳入重試次數(shù)(times)和重試等待時間(wait_time)置媳,對待測用例實行重試機制于樟。
pytest里的出錯重試機制實現(xiàn)
在測試框架pytest里,已經(jīng)實現(xiàn)了有關出錯重試的策略拇囊,我們首先需要安裝一個此類的插件迂曲,在cmd內(nèi)執(zhí)行以下命令安裝:
pipinstallpytest-rerunfailures
如果你需要將此機制應用到所有的用例上,那么請在執(zhí)行的時候使用如下命令(reruns是重試次數(shù)):
pytest--reruns5
來執(zhí)行你的用例寥袭;
如果你期望加上出錯重試的等待時間路捧,請使用如下命令(reruns-delay是等待時間):
pytest--reruns5--reruns-delay1
來執(zhí)行你的用例;
如果你只想對某幾個測試用例應用重試策略传黄,你可以使用裝飾器:
@pytest.mark.flaky(reruns=5,reruns_delay=2)
例如:
@pytest.mark.flaky(reruns=5,reruns_delay=2)
deftest_example():
importrandom
assertrandom.choice([True,False])
更詳細的介紹請參閱官方文檔?杰扫。
Allure里的測試用例分層
剛剛我們實現(xiàn)了用例的出錯重試機制,但是這僅僅解決了腳本在不穩(wěn)定環(huán)境下的穩(wěn)定性膘掰;如果還想要腳本變得更加容易維護章姓,除了傳統(tǒng)的po模式使用例和元素分離之外,我們還可以引入測試用例分層機制。
為什么要采用分層機制啤覆?
傳統(tǒng)的po模式苍日,僅僅實現(xiàn)了用例和元素分離,這一定層面上保障了用例的可維護性窗声,起碼不必頭疼于元素的變更會讓用例到處失效相恃;但是這還不夠,例如笨觅,現(xiàn)在有三個case拦耐,他們都包含了以下步驟:登錄、打開工作臺见剩、進入個人中心杀糯;那么如果不做分層,這三個用例會把這三個步驟都寫一遍苍苞,如果某天頁面的變動導致其中一個步驟需要更改固翰,那么你不得不去每個用例里去更新那個步驟。
而如果羹呵,我們把用例當做是堆積木骂际,登錄、打開工作臺冈欢、進入個人中心這三個步驟都只是個積木歉铝,那么我們寫用例的時候,只需要在用到這個步驟時凑耻,把積木搭上去太示;如果某一天,其中一個積木的步驟有變動香浩,那么只需要去更改這個積木的內(nèi)容类缤,而無需在每個使用了這個積木的用例里去改動。
這大大增強了用例的復用性和可維護性弃衍,這就是采用分層機制的原因呀非,下面,我會就allure里的分層機制做介紹來討論具體如何實現(xiàn)镜盯。
allure的裝飾器@step
在allure里岸裙,我們可以通過裝飾器@step完成分層機制,具體的速缆,當你用@step裝飾一個方法時降允,當你在用例里執(zhí)行這個方法,會在報告里艺糜,表現(xiàn)出這個被裝飾方法剧董;而@step支持嵌套結(jié)構(gòu)幢尚,這就意味著,你可以像搭積木一樣去搭你的步驟翅楼,而他們都會一一在報告里被展示尉剩。
下面直接用allure的官方示例作做舉例:
importallure
importpytest
from.stepsimportimported_step
@allure.step
defpassing_step():
pass
@allure.step
defstep_with_nested_steps():
nested_step()
@allure.step
defnested_step():
nested_step_with_arguments(1,'abc')
@allure.step
defnested_step_with_arguments(arg1,arg2):
pass
deftest_with_imported_step():
passing_step()
imported_step()
deftest_with_nested_steps():
passing_step()
step_with_nested_steps()
運行這個case后,報告是這樣的:
可以看到毅臊,
test_with_nested_steps由passing_step()和step_with_nested_steps()這兩個方法組成理茎;
而step_with_nested_steps()又由nested_step()組成;
nested_step()又由nested_step_with_arguments(1, 'abc')組成管嬉;
這樣就像搭積木一樣皂林,組成了測試用例;而在報告里蚯撩,也層級分明的標識了步驟的嵌套結(jié)構(gòu)础倍。
這樣,我們就可以通過一個又一個@step裝飾的方法胎挎,組成測試用例沟启;同時報告里也會支持層級顯示;從而完成我們的分層機制呀癣。