- 原田達也
- 約 1,800 文字
- 2,700 View
はじめに
はじめまして。Technology Inovation Group (TIG) の原田と申します。
以前はGoを使ってアプリ開発していたのですが、ここ最近はPythonを書くことが多いです。
Pythonのテストではpytestを使うことが多く、その中で「テストケースごとに違うデータを事前準備したい」というモチベーションが発生したので、pytestを使用して実装していきます。
前提
以下の読者を想定しています。
- Pythonやpytestは多少触ったことがある
- 環境構築は完了している
できること
- 複数のテストケースごとに異なる事前処理・事後処理ができる
- 事前処理と事後処理を分離してテストコードをスッキリかける
環境
- Python 3.12.4
- pytest 8.3.3
やってみる
※ツールの導入方法に関しては今回は割愛します。
まずはそれぞれの機能のおさらいをします。
parametrize
parametrizeは一言で言うと「テストケースに複数の異なる入力や条件を渡して、同じテスト関数を何度も異なるデータで実行できる機能」です。
例えば、以下のような関数をテストしたいとします。
def add(x, y): |
これに対して複数の条件のテストを実行するには以下のように記載します。
pytest.paramに指定した変数が先頭から順にテスト関数の変数に渡されるイメージです。
idはテストケースに名前を付けられます。可読性も向上するのでお勧めです。
import pytest |
これを実行すると以下のように表示されます。
期待通り、3つのテストケースが実行されていることが確認できますね。
(表示の都合上失敗させています)
test_main.py::test_add[normal1] PASSED [ 33%] |
fixture
fixtureは一言で言うと「テスト関数の前に特定の状態や環境を準備するための仕組み」です。
yieldを使用するとテスト関数実行後のteardown処理も実行でき、非常に便利です。
例えばDBに事前にデータを投入したい場合を考えます。
import pytest |
このfixtureを利用するにはテスト関数に引数として渡してあげます。
def test_hoge_function(db_setup): # 引数にfixtureを渡す |
これを実行すると以下のように表示されます。
期待通り、セットアップとクリーンアップが実行されていることが確認できますね。
(表示の都合上失敗させています)
test_main.py::test_hoge_function FAILED [100%] |
fixture & parametrize
ではいよいよ本題に入ります。
「テストケースごとに違うデータを事前準備したい」という目的ですが、これは「fixtureに対して、parametrizeで異なる変数を渡したい」と言い換えることができます。
fixtureを紹介した時のhoge_functionのテストコードを再掲します。
def test_hoge_function(db_setup): # 引数にfixtureを渡す |
これをparametrize化しましょう。引数にfixture(db_setup)を渡しているので、parameterizeにも同じ変数名を指定します。そして、引数indirectにfixture名を渡します。
テスト関数に直接渡す変数に関しては、indirectに指定しません。
以下の図ようなイメージで変数が渡されます。
重要: fixtureをindirectに指定する
以下の例の場合、db_setupをindirectに指定しているので、テストデータxはfixtureに渡され、「期待値x」はテスト関数に直接渡されます。
import pytest |
fixtureでparametrizeからの変数を受け取る場合、引数にrequestをとり、request.paramとすることでアクセスできます。
重要: parametrizeで渡される変数にアクセスするにはrequest.paramでアクセスする
import pytest |
全てのコードは以下の通りになります。
import pytest |
これを実行すると以下のように表示されます。
冗長になるので一部表示を省略していますが、期待通りセットアップとクリーンアップがテストケースごとに実行されていることが確認できますね。
(表示の都合上失敗させています)
test_main.py::test_hoge_function[case1] FAILED [ 33%] |
まとめ
parametrizeでfixtureに変数を渡す際にはindirectに指定するfixtureでparametrizeから渡される変数にアクセスするにはrequest.paramでアクセスする
parametrizeとfixtureをうまく使用することで、テスト処理と準備処理を分離し、すっきりとした見通しの良いテストコードを整備できます。
parametrizeとfixtureを同時に使用する際の書き方について少し沼にはまったので、記事にしました。
同じく沼にはまりそうになっている方の一助になれば幸いです。
ここまでご覧いただきありがとうございました。