5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ざっくり分かるpytestのfixture

Last updated at Posted at 2022-05-09

pytestにおけるfixtureとは

  • テストの事前処理、事後処理を記載できるpytestの機能です。
  • SetUp(事前処理), TearDown(事後処理)を1つの関数で書けます。
  • setup_class, setup_functionのように、スコープごとに違う関数を呼ぶ必要がありません。
  • fixtureからfixtureを呼び出すことができ、処理を階層的に記述できます。

SetUp, TearDownじゃダメなの?

  • ダメかと言われるとダメじゃありません。チーム内でスタイルが統一されている方が大事です。
  • 機能面だけで言うと、pytestにおいてはfixtureを利用する方がリッチではあります。
  • ブラウザ操作自動化ツールであるPlaywright for Pythonはfixtureを利用しています。
    • 上記を採用する場合、可読性と保守性の観点からfixtureに統一することを勧めます。

基本的な構文

import pytest


@pytest.fixture(scope="function")  # fixtureの宣言
def hoge():
    # setup
    message = "ほげ"

    # test
    yield message

    # teardown
    print("done")

def test_print(hoge):
    print(hoge)

実行結果:
ほげ
done

上記のように、

  • @pytest.fixture(scope="~~~") とデコレート文を書いた次の関数がfixtureになります。
  • scope="~~~"は実行の粒度を指します。(参考)
    • "function" : テストメソッドごと
    • "class" : テストクラスごと
    • "module" : スクリプト(ファイル)ごと
    • "session" : pytestコマンド実行ごと
  • 呼ぶ側は引数にfixtureを指定します。
  • fixture側でyield (続く処理がない場合はreturn)すると呼び出し元に値を引き渡せます。

とりあえずこれだけ知っておけば最低限使えると思います。

実例: fixtureを使ったディレクトリ作成① autouse=True

ではもう少し深堀りして、fixtureを使ったディレクトリ作成を試します。
これはテストのスクリーンショットを実行ごとに保存する際などに使えます。

ここでは下記のディレクトリ構成を想定し、テスト実行時にその実行日時のディレクトリをoutputs/以下に生成します。

.
    tests/
        outputs/
            {%y%m%d-%H%M%S}/  # 今回の作成対象ディレクトリ
        conftest.py
        test_makedir.py

fixtureは設定ファイルconftest.py中に記載すると全てのテストスクリプトから呼び出せます。

conftest.py
import os
from datetime import datetime
 
import pytest
 
PATH_OUTPUTS = "./tests/outputs"
 
 @pytest.fixture(scope="session", autouse=True)
 def parentdir():
     name_parentdir = datetime.now().strftime("%y%m%d-%H%M%S")
     path_parentdir = os.path.join(PATH_OUTPUTS, name_parentdir)
     os.makedirs(path_parentdir)
     return path_parentdir
test_makedir.py
class TestMakeDir:
    def test_makedir(self): # 以下省略

テストメソッドの引数にparentdirを指定してないことに気付いたら鋭いですね。
autouse=Trueを付けることで、テストメソッドで呼び出さなくてもfixtureを呼び出せます。

実例: fixtureを使ったディレクトリ作成② 階層的なfixtureの呼び出しとbuilt-in fixture

もう少し複雑な例として、上記の実例を修正を加え、テストメソッドの属するクラスごとに更にディレクトリを作成してみます。
下記のディレクトリ構成を想定し、テスト実行時にoutputs/{%y%m%d-%H%M%S}/以下に、
実行されたテストクラスのディレクトリを生成します。

.
    tests/
        outputs/
            {%y%m%d-%H%M%S}/
                TestMakeDir  # 今回の作成対象ディレクトリ
                TestMakeDirTwo  # 今回の作成対象ディレクトリ
        conftest.py
        test_makedir.py

この場合、conftest.pyは以下のようになります。

conftest.py
import os
from datetime import datetime
 
import pytest
 
PATH_OUTPUTS = "./tests/outputs"
 
 @pytest.fixture(scope="session", autouse=True)
 def parentdir():
     name_parentdir = datetime.now().strftime("%y%m%d-%H%M%S")
     path_parentdir = os.path.join(PATH_OUTPUTS, name_parentdir)
     os.makedirs(path_parentdir)
     return path_parentdir

 @pytest.fixture(scope="class")
 def classdir(request, parentdir) -> str:
     path_classdir = os.path.join(parentdir, request.node.name)
     os.makedirs(path_classdir)
     return path_classdir
test_makedir.py
class TestMakeDir:
    def test_makedir(self, classdir): # 以下省略

class TestMakeDirTwo:
    def test_makedir_two(self, classdir): # 以下省略

まずfixtureclassdirの引数にparentdirが指定されていることに注目してください。
ここではfixtureparentdirが返却するpath_parentdirを変数parentdirに格納しています。

もう一つ、fictureclassdirにはrequestというimportもされていない謎の引数もありますね。
これはpytestにビルトインされているfixtureで、importなしで使えます。
request.node.nameには呼び出したノードの名前、すなわちTestMakeDirTestMakeDirTwoが格納されています。これで最終的な出力ディレクトリが生成できます。

requestの他にも色々なbuilt-in fixtureがあるので、調べてみてください。

まとめ

fixtureを使いこなすと夢が広がります。

参考

しっかり理解したい方は公式ドキュメントを参照ください。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?