以前、Javaで不安定なテスト(flakyなテスト)をリトライさせるライブラリを素振りしました。今回の記事はPython版です。
Pytestの公式ページにてFlakyなテストに対する解決策となるライブラリを複数提示されており、その中でもGitHubのStar数が一番多かったflakyを素振りすることにします。
ユースケース
E2E試験等の不安定(flaky)なテストを、失敗時に再実行させて全体として安定させたい。
環境
- Python
- 3.8.5
- pytest
- 6.2.4
- flaky
- 3.7.0
インストール方法
pip install flaky
設定値
max_runs
最大何回まで再実行するかを設定する。デフォルト値は2回。
min_passes
何回テストが成功するまで再実行するか設定する。規定数まで成功したら、それ以降のテストは行わない。デフォルト値は1回。
rerun_filter
再実行する際に実行したいメソッドを設定する。自分で振る舞いを設定できるので自由に設定できます。flaky公式ページでは、2例紹介されていました。
- 実行するたびに安定性のために1秒waitする
- 特定のエラーが発生したら終了する
実行するたびに安定性のために1秒waitする
import time def delay_rerun(*args): time.sleep(1) return True @flaky(rerun_filter=delay_rerun) def test_something_else(): assert 1 == random.choice([1, 2, 3])
特定のエラーが発生したら終了する
RuntimeError
が発生したら1回で終了する。flaky公式では自作例外を使用していました。
def is_not_crash(err, *args): return not issubclass(err[0], RuntimeError) @flaky(rerun_filter=is_not_crash) def test_something_else(): raise RuntimeError
使い方
テストごとにアノテーションで設定
メソッドに@flaky
アノテーションを付与します。設定については、上に記載しているとおりです。
from flaky import flaky def rerun_log(err, *args): print("*再実行します*") return True @flaky(max_runs=3, min_passes=2, rerun_filter=rerun_log) def test_1(): assert 1 == 2
CLIで設定
CLIから再実行設定する
pytestのオプションに--force-flaky
を付与することで、各テストにアノテーションを付与していなくても、再実行設定を付与できます。デフォルト値で再設定します。
pytest --force-flaky
CLIから詳細な再実行設定をする
pytestのオプションで--force-flaky
を設定し、--max-runs=nun
と--min-passes=num
を付与すると最大実行数、規定数を設定できます。
ただし、アノテーションで付与している設定値の上書きはできません。また、rerun_filter
に関してはCLI上からは設定できません。
pytest --force-flaky --max-runs=4 --min-passes=2
アノテーションで付与した設定を無視する
アノテーションで付与した設定を無視できます。
テストを作りこんでいる最中に再実行設定が有効になっていると、TDD等でテストを快適に書けませんので、こちらの設定には大きな価値があります。
pytest -p no:flaky
その他
再実行したテストのテストレポートの出し方を変更できます。
# 再実行したテストはテストレポートに出さない --no-flaky-report # 再実行したテストは短いテストレポートにする --no-success-flaky-report
ソースコード
終わりに
現在、SalesforceをE2Eでテストしているのですが、Salesforce側のエラーでFlakyになるので困っています。手動ならリトライは簡単なんですがね…。
今回のライブラリ:flakyを入れたことで安定して稼働してほしいです。
この記事がお役に立ちましたら、各種SNSでのシェアや、今後も情報発信しますのでフォローよろしくお願いします。
参考記事
- Flaky tests — pytest documentation
- GitHub - box/flaky: Plugin for nose or pytest that automatically reruns flaky tests.