# Flaky tests ###### tags: `unit-test` `pytest` ## 序言 在各種程式與環境組合起來運行時,我們常常會遇到一個問題: **這段code剛剛在我的電腦上還會動阿?怎麼到別台電腦就壞了?** 環境的不同/網路連線狀態的差異/port設定/ENV設定/random seed...有太多種可能 這種不穩定的情況若是在測試過程中發生,我們就稱之為 Flaky Test ## flaky有什麼問題? 問題可大了,如果有個穩定的CI運行,所有測試都必須通過才能merge對吧? 如果有幾個測試處於flaky的狀態,CI跑得不順不說,每次不過包含開發與review的人大概都會跑去看發生了什麼事 一方面浪費時間,一方面會阻礙工程師發現真正重要的問題。 ## 什麼情況下會不穩定 其實有相當多種情況,除開序言提及的情況外,也有可能是測試運行的順序干擾了測試的結果(例如用了平行跑測試的模組),與db的連接不穩定導致測試中沒有teardown清完該清的東西... 而我遇到這個情況是在使用datastore emulator時,由於這個db是eventual consistency,導致塞entity進去後assert變成薛丁格的測試,當下想說會不會是塞完entity後要讓db反應一下停個幾秒,但後來還是不穩定,才知道了flaky這個概念。 ## 怎麼解決flaky 如果不穩定的原因是可以掌控的,例如ENV/PORT沒有寫成設定值、teardown沒清乾淨等等還能靠修code解決,但是如果像上一段連接db的問題,有時候想修也無從修起。 當我們認定某些不穩定的測試是人為無法掌控其測試穩定度,但又希望這種穩定度不會過度干擾到開發流程的狀況下,我們可以用pytest的伴生函式庫pytest-rerunfailures來解決 https://github.com/pytest-dev/pytest-rerunfailures 當然還有其他選擇,不過pytest-rerunfailures就是由pytest自家人開發的,可以方便的用裝飾器掛上測試,跟其他的pytest函式庫也有較好的結合,以下就給一些簡單的範例。 我們已前一章節連接datastore的問題來舉例 ```python= # test_create_entity @pytest.fixture(autouse=True) def put_entity(): """ put 3 entity into db first """ # insert 3 entity into db # code here..... # 設定一共可以跑幾次/每次間隔時間 @pytest.mark.flaky(reruns=5, reruns_delay=1) def test_create(): """ test to create entity """ # start from an empty db, so we assume we see 3 entities now entity = xxxDAO.get_all() assert len(entity) == 3 ``` 在沒有flaky的情況下,由於datastore eventual consistency的特性,導致在assert的當下,datastore可能並沒有及時的把entity塞進去,如果如以上程式碼將flaky加入,我們就可以設定當測試失敗時,共可以重跑幾次,其中有一次成功,在測試結果上就會算通過,CI就會放行。 ## 結語 我們得知了在測試時若有某些測試單元出現不穩定狀況時,該如何用re-run的方式"暫時"解決這個問題的方式。 當然,若以最好的狀況來看,不穩定的測試若出現,通常應該依靠重寫/分拆測試的方式嘗試解決。 但若由於時間或天然限制的因素,導致無法短時間內解決這種不穩定,我們可以重新運行不穩定的測試嘗試讓他們通過,提供額外的機會來減輕不穩定測試的負面影響,從而使CI的流程不會頻繁失敗。 那麼以上就是有關flaky test的些許隨筆,我們下次再見。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up