pytest-xdistとは
pytest-xdist
はテストの並列実行・分散実行に使うpytest
のプラグインです。
これをインストールし、実行時に並列ノード数をオプションとして渡すだけで、勝手にテストを振り分けて実行してくれます。
本記事ではpytest-xdist
を実際に使ってみて分かった便利な使い方、オプションなどをメモとしてまとめます。
なお、私はpytest
をユニットテストではなく、主にSelenium
やPlaywright
を使ったUIテスト用途に利用しているため、それに特化した内容になっていることをご承知おきください。
内容は随時更新します。
インストール
pip install pytest-xdist
テストの並列実行
pytest -n 4 test.py
-n
のあとにテストを並列実行するノード数(ワーカー数)を入力します。
数値の代わりにauto
を指定すると利用可能なCPUのコア数が自動的に代入されます。
pytest -n auto test.py
コア数以上の値を代入すればノードをその分だけ展開することも可能ですが、CPUのコア数の制限を受けます。
展開したノード上で厳密な並列処理はできないことに注意ください。
ノードの特定
pytest-xdist
の実行時にはworker_id
fixtureが呼び出せます。
これを使うと、テストを実行したノードの特定が可能です。
def test_worker_id(self, user_id):
hoge = f"このテストは{user_id}で実行されています"
# fixture user_idにworker id(gw0, gw1, ...)が入る
print文の出力
pytest-xdist
を使用すると、pytest
で利用可能な-s/--capture=no
オプションが無効化され、そのままではprint文を表示することができなくなります。
print文を表示させたい場合は標準エラーに出力してください。
import sys
def test_print_worker(self, user_id):
message = "(ワーカーごとの処理結果)"
print(f"{user_id}: {message}", file=sys.stderr)
オプション入力の省略(設定ファイル)
pytest-xdist
実行時のオプションが固定化されている場合、設定ファイルpyproject.toml
を作成し、以下のように記載することで毎回のオプション入力を省略できます。
[tool.pytest.ini_options]
addopts = "-n auto"
pytest
の設定ファイルにはpyproject.toml
の他にpytest.ini
なども利用できます。
poetry
など他ツールとの一元管理ができるpyproject.toml
に優位性があると考え、私はpyproject.toml
による設定を採用しています。
https://docs.pytest.org/en/7.0.x/reference/customize.html
全ノードでの同一テストの実行
UIテストでは、稀に「同時にnブラウザからアクセスする」といった負荷テスト的な項目を確認する場合があります。
この際はpytest-xdist
のdist
オプションを以下のように指定すれば全ノードで同じテストを実行できます。
pytest -n 4 --dist each test.py
負荷テストそれ自体は基本的にAPIリクエスト等を経由して実現するほうが効果的です。
あくまでUI経由で実行する合理的な理由がある際にのみこの方法を採用するといいと思います。
余談: pytest-parallelについて
pytest
でテストを並列実行できるプラグインとして、pytest-parallel
というものも存在します。
pytest-parallel
のpytest-xdist
に対する優位点は以下の3点であると述べられています。
pytest-parallel is better for some use cases (like Selenium tests) that:
- can be threadsafe
- can use non-blocking IO for http requests to make it performant
- manage little or no state in the Python environment
スレッドセーフであるため、並列実行においてはpytest-parallel
の方がより安全であると言えます。
しかし一方で使用者の多さ、プラグインの更新頻度、Issueに対するレスポンスの良さなどはpytest-xdist
の方が勝る印象です。
私はpytest-xdist
を優先的に利用しています。