【pytest】独自markで共通処理を作成する
pytestでユニットテストを書く際に、独自markについて調べたのでメモ
やりたかったこと
各テスト関数の実行前にパラメータ付きの初期化処理を実行したい。
他の共通処理はfixtureを使って、実装していたが今回はパラメータ付きであったためfixtureは利用できなかった。
標準のmarkであるparametrizeは、引数を指定できるので独自markを作れば実現できると判断し調査した。
@pytest.mark.usefixtures('my_fixture') # fixtureだと引数を指定できない def test_target_1(): sample.target() @pytest.mark.parametrize('param1, param2', [ # parameterizeは引数を指定してる (1, 2), (2, 3), ]) def test_target_2(my_fixture, param1, param2): sample.target()
使い方
テスト関数にmarkを付与する
対象のテスト関数に独自markの使用を記述する(今回は「my_init」が独自mark)
@pytest.mark.my_init(param1="テスト", param2=2) # 初期化で使用する引数を設定 def test_target_3(): sample.target()
markに対する処理の実装
pytestのドキュメントに記載があるやり方は、hooksを利用してテスト実行時にmarkが付与されていれば独自処理を実行する方法。
Working with custom markers
conftest.py
def pytest_runtest_setup(item): for marker in item.iter_markers(name="my_init"): # 独自markがついているとき初期化処理を呼び出す # marker.args, marker.kwargsで引数を参照可能 _my_init(**marker.kwargs) def _my_init(param1: str = None, param2: int = None): # テスト初期化処理などを記述する pass
ただ、hooksの関数内ではfixtureを参照できなかった。
def pytest_runtest_setup( my_fixture, # fixtureの参照はできない item ): for marker in item.iter_markers(name="my_init"): _my_init(**marker.kwargs)
今回は初期化処理内でfixtureを利用したかったため、公式の方法だと不足。
調べているとfixtureからでもmarkが付与されているか取得できるらしいので、そっちの方法を採用。
conftest.py
@pytest.fixture( scope="function", # 関数単位の実行 autouse=True # 自動でfixtureを実行する ) def my_init_fixture(request): for marker in request.node.own_markers: if marker.name=="my_init": # fixtureを参照する my_fixture = request.getfixturevalue("my_fixture") # 独自markのとき _my_init(my_fixture, **marker.kwargs) def _my_init(my_fixture, param1: str = None, param2: int = None): # テスト初期化処理などを記述する pass
独自markの登録
このままだと、テスト実行時に未確認のmarkであると警告が出てしまう。
PytestUnknownMarkWarning: Unknown pytest.mark.my_init - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html @pytest.mark.my_init()
設定ファイルかhooksで、markを登録する。
設定ファイルで登録する場合
pytest.ini
[pytest] markers = my_init(param1=None, param2=None): markの説明を書く
hooksで登録する場合
conftest.py
def pytest_configure(config): config.addinivalue_line( "markers", "my_init(param1=None, param2=None): markの説明を書く" )