【初心者〜現場で活躍まで】挫折しないPython勉強方法もっと知る

【pytestで前処理・後処理】fixtureの使い方

【pytestで前処理・後処理】fixtureの使い方

pytestのfixtureを使えば、短いコードで簡単に、前処理・後処理を書けます。

エソラ

この記事では、pytestのfixtureの書き方を詳しく解説します。

この記事を書いた人

エソラ
  • エンジニア歴10数年
  • SIerでDX推進を仕事に
  • Python、AWSを使ったアーキテクチャ設計・アプリ開発が得意
  • 30代、2児の父でサウナ好き
  • [icon-class=”icon-twitter”]Twitter

ちなみに、私の環境のバージョン情報は以下の通りです。

項目バージョン
Python3.10.6
pytest7.1.3
バージョン情報

それでは、最後までよろしくお願いします。

目次

fixtureとは?

fixture(フィクスチャ)を使えば、テストの前処理、後処理を書けます。

pytest以外のxUnitに詳しいなら、fixtureはsetup()、teardown()に相当すると考えると理解しやすいです。

fixtureを使うと、テスト関数から前処理・後処理を分離できて、シンプルで保守性の高いテストコードが書けます。

fixtureの前処理・後処理でよくやる処理例は以下の通り。

項目よくやる処理例
前処理DBのセットアップ
モック化
パラメータ化
後処理DBのクローズ処理
tempファイルの削除処理
fixtureの前処理・後処理でよくやる処理例

fixtureの使い方

fixtureを使うには、@pytest.fixture()をメソッドの前に書きます。

import pytest


class TestFixtures():

    @pytest.fixture()
    def sample(self):
        print("前処理")
        yield
        print("後処理")

    def test_hoge(self, sample):
        print(sample)
        print("本処理")
        assert 1 == 1

着目すべきはyieldです。以下のルールがあります。

  • yieldの手前にあるコードは前処理として、実行
  • yieldの後ろにあるコードは後処理として、実行

実行すると、以下のようになります。

$ pytest -s test_fixture_before_after.py 
======================================================== test session starts ========================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 1 item                                                                                                                    

test_fixture_before_after.py 前処理
None
本処理
.後処理


========================================================= 1 passed in 0.01s =========================================================

fixtureのスコープ

fixtureでは以下の通り、スコープを定義できます。

スコープ説明
scope=’function’テスト関数ごとに、一回実行(デフォルト)
scope=’class’テストクラスごとに、一回実行
scope=’module’モジュール(ファイル)ごとに、一回実行
scope=’package’パッケージごとに、一回実行
scope=’session’セッション(pytestコマンドでテストを実施)ごとに、一回実行。
fixtureのスコープの種類

スコープを明示的に指定しない場合、デフォルトのスコープはfunctionになります。

スコープの書き方

スコープの書き方は@pytest.fixture(scope=’XXX’)でスコープを指定します。

functionであれば、@pytest.fixture(scope=’function’)と書きます。

スコープの実行順序

では、スコープがどのように動くのか実際に見てみましょう。テストコードのサンプルは以下の通りです。

  • fixtureのスコープは、function、class、module、sessionを指定
  • テストモジュールは1つ
  • テストクラスは2つ
  • テスト関数は、合計4つ(テストクラスに2つずつ)
import pytest

@pytest.fixture(scope='function')
def fixture_function():
    """
    テスト関数ごとに、一回実行
    """
    print('前処理: function')
    yield
    print('後処理: function')

@pytest.fixture(scope='class')
def fixture_class():
    """
    テストクラスごとに、一回実行
    """
    print('前処理: class')
    yield
    print('後処理: class')

@pytest.fixture(scope='module')
def fixture_module():
    """
    モジュール(ファイル)ごとに、一回実行
    """
    print('前処理: module')
    yield
    print('後処理: module')

@pytest.fixture(scope='session')
def fixture_session():
    """
    セッション(pytestコマンドでテストを実施)ごとに、一回実行
    """
    print('前処理: session')
    yield
    print('後処理: session')


class TestFixtureScope_2():

    def test_1(
            self,
            fixture_function,
            fixture_class,
            fixture_module,
            fixture_session):
        pass

    def test_2(
            self,
            fixture_function,
            fixture_class,
            fixture_module,
            fixture_session):
        pass


class TestFixtureScope_1():

    def test_1(
            self,
            fixture_function,
            fixture_class,
            fixture_module,
            fixture_session):
        pass

    def test_2(
            self,
            fixture_function,
            fixture_class,
            fixture_module,
            fixture_session):
        pass

実際に実行した結果が、以下です。

$ pytest -vs test_fixture_scope.py 
======================================================== test session starts ========================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0 -- /Users/y5a1m5a/Documents/workspace/python-sample/pytest-demo/venv/bin/python3.10
cachedir: .pytest_cache
rootdir: (省略)
collected 4 items                                                                                                                   

test_fixture_scope.py::TestFixtureScope_2::test_1 前処理: session
前処理: module
前処理: class
前処理: function
PASSED後処理: function

test_fixture_scope.py::TestFixtureScope_2::test_2 前処理: function
PASSED後処理: function
後処理: class

test_fixture_scope.py::TestFixtureScope_1::test_1 前処理: class
前処理: function
PASSED後処理: function

test_fixture_scope.py::TestFixtureScope_1::test_2 前処理: function
PASSED後処理: function
後処理: class
後処理: module
後処理: session


========================================================= 4 passed in 0.03s =========================================================

スコープごとの前処理、後処理の呼び出し回数は以下の通りです。

スコープ呼び出し回数
function4回
class2回
module1回
session1回
スコープごとの呼び出し回数

ここでスコープの動作について分かることは、以下の通りです。

  • functionはテスト関数、classはテストクラス、moduleはファイルの数だけ実行
  • sessionはテストを通じて、一回だけ実行
  • 前処理は、スコープの広いsessionから、狭いfunctionの順で処理を実施
  • 前処理は、スコープ狭いfunctionから、広いsessionの順で処理を実施
エソラ

この特徴をしっかりと覚えて、スコープを定義すれば、とても便利にfixtureが使えます。

fixtureでパラメータ化する方法

一つの関数に対して、様々なデータセットで検証したい時は、パタメータ化テストがシンプルに書けるので、便利です。

pytestでのパラメータ化テストは3つの方法があります。

パラメータ化する3つの方法
  • テスト関数をパラメータ化:最もスタンダード
  • fixtureをパラメータ化:前処理、後処理を書きたい時に利用
  • フック関数(pytest_generate_tests)で、パラメータ化:複雑なデータセットを書きたい時に利用

fixtureを使ってパラメータ化することで、パラメータに応じた前処理・後処理を書くことができます。

少ないコードで様々なデータパターンのテストができるのがメリットですね。上手く使えば、生産性・品質向上して、周りの人の評価もあがりますね。

エソラ

パラメータ化は現場でテストコード書くなら、絶対に利用します。必ずマスターして下さい。

以下にpytestでパラメータ化する方法について詳しく解説した記事があります。もちろんサンプルコードありです。

conftest.pyでfixtureを複数のテストファイルで共有する

複数のテストファイルでfixtureを共有したい時は、conftest.pyに定義すれば、簡単に共有ができます。

conftest.pyのサンプルは以下の通りです。

import pytest


@pytest.fixture(scope="session")
def conf():
    print("conftest:前処理")
    yield
    print("conftest:後処理")

そして、実際に使ってみます。

conftest.pyを利用する時、import文は不要で、テスト関数の引数にfixtureを定義した関数を渡します。

def test_conf(conf):
    pass

実行結果は、以下の通りです。

$ pytest -vs test_conf.py 
======================================================== test session starts ========================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0 -- /Users/y5a1m5a/Documents/workspace/python-sample/pytest-demo/venv/bin/python3.10
cachedir: .pytest_cache
rootdir: (省略)
collected 1 item                                                                                                                    

test_conf.py::test_conf conftest:前処理
PASSEDconftest:後処理


========================================================= 1 passed in 0.01s =========================================================

autouseを指定する

常に使うfixtureがある場合、fixtureの引数にautouse=Trueを指定すると便利です。

書き方は以下の通り。

@pytest.fixture(scope=”function”, autouse=True)

テストコードのサンプルは以下の通り。

import pytest


@pytest.fixture(scope="function", autouse=True)
def fix_autouse():
    print("autouse")


def test_1():
    pass

test_1関数の引数にfix_autouseがないとfixtureが動きませんが、autouse=Trueを指定しているので、引数なしでも動きます。

これを実行した結果が以下です。

$ pytest -vs test_autouse.py 
======================================================== test session starts ========================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0 -- /Users/y5a1m5a/Documents/workspace/python-sample/pytest-demo/venv/bin/python3.10
cachedir: .pytest_cache
rootdir: (省略)
collected 1 item                                                                                                                    

test_autouse.py::test_1 autouse
PASSED

========================================================= 1 passed in 0.00s =========================================================

前処理が実施されていることが分かります。

まとめ:fixtureを使えば、テストコードの幅が広がる

ここまで、fixtureの書き方を解説しました。

fixtureを有効活用することで、高度な前処理、後処理が短いコードで書けます。

前処理、後処理が書けると、テストコードの幅が広がります。それが品質の確保、向上に繋がるので、しっかりと使い方をマスターしましょう。

もっとpytstの使い方を学びたい場合は、以下の書籍がおすすめです。

日本語で唯一、pytestだけに焦点を当てて、詳細に書かれた書籍です。

テスト駆動Python第2版
総合評価
( 5 )
メリット
  • 日本語でpytestの全てについて、解説されている唯一の書籍
  • 段々とステップアップして、深くなるので、初心者でも、中級者でも、上級者でも、学びがある
  • サンプルコードには、サンプルアプリが含まれているため、実践的に学べる工夫あり
  • 章末にまとめがあり、復習の役に立つ
  • 第7章に「どのようなテストを書くのか」についての解説があり、テストに対する考え方が深まる
デメリット
  • 後半になると、かなり高度な内容になるため、初心者には難しい
  • タイトルに「テスト駆動開発」と書かれているが、該当部分の記述が少なく、テスト駆動開発を知りたい人は期待外れになるかも
エソラ

間違えて、第1版を買わないように注意して下さい。

著:Brian Okken, 翻訳:株式会社クイープ, 監修:株式会社クイープ, 監修:安井 力
¥2,970 (2022/11/24 04:05時点 | Amazon調べ)

Pythonの勉強方法は、まとめ記事があります。

Pythonを勉強する時、何から勉強するか分からず、挫折します。初心者でも、中級者でも、レベルに合わせた勉強方法を分かりやすくまとめています。

ここまでお読みいただき、ありがとうございました。

役に立った、面白かったと思ったら、SNSでシェアしてくれると嬉しいです。

エソラ

もし分からないことがあれば、お問い合わせTwitterにご連絡をいただけると嬉しいです。(Twitterの方が返信早いかも…)

\ 更新の励みになるので、ポチッとしてね /

エソラ

他にもスキルアップやキャリアアップの役に立つ情報が満載です。他の記事も読んで、ゆっくりしていってね!

【pytestで前処理・後処理】fixtureの使い方

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次