雑記

pytest のフィクスチャとは、以下の擬似コードのように1回だけ yield するジェネレータ関数の形式でテスト時の要請(前処理、ほしいもの、後処理)を登録しておくと、テストに関数名と同名の引数を取ることでテスト実行時に要請が実行され、その引数にほしいものが渡されてくる制度といえると思います(通常の関数の形式でもよく、その場合はしてほしい後処理がないことになります)。pytest 側がテスト実行前にフィクスチャの目印がついた関数(組み込みのものもユーザ定義のものも)を全て読み込んでおいてくれてそのように取り計らってくれるという意味です。テスト社会においてもこういった福利厚生制度が求められているのだと思います。

@pytest.fixture  # これはフィクスチャに登録するという目印
def hoge():  # これがフィクスチャ名
    ...  # テスト前にこれをしてほしい、という要請をかく
    yield x  # テストのときにこれを渡してほしい(あるいは何も要らない)、という要請をかく
    ...  # テスト後にこれをしてほしい、という要請をかく

# テストにフィクスチャ名と同名の引数を設定する( =「フィクスチャをリクエストする」)と
# pytest コマンドでのテスト実行時に要請が実行される
# つまりテストの引数に hoge と記述することでそのテストで上の要請を実行させることができる
# このとき hoge にほしいもの x が格納されてくる(何も yield しなかったら hoge は None である)

より細かいことをいうと、フィクスチャ名はジェネレータ関数名と必ず同名ではなく変更することもできますし、テストの前後処理というのがそのテストの実行前後でするのか1ファイル内の全てのテストの実行前後でするのかといったスコープの概念もありますし、明示的にテストの引数に記述しなくても要請を実行させるオプション autouse などもありますが上記の説明では捨象しています。

# https://docs.pytest.org/en/6.2.x/reference.html#pytest-fixture
@pytest.fixture(scope='session', autouse=True, name='kono_namae_de_yonde')

そして大切なことは、上のように自分でせっせと要請を記述してフィクスチャとして登録しなくても、便利そうな要請が既に色々 pytest に組み込まれているということです。
pytest fixtures: explicit, modular, scalable — pytest documentation

Pytest has useful built-in fixtures, listed here for reference:


以下、上の擬似コードでの hoge() を「フィクスチャジェネレータ関数」、x を「フィクスチャ値」とよぶことにします。実際、pytest のリポジトリ中で後者は _FixtureValue 型とされていると思います。


フィクスチャジェネレータ関数もまたテストのようにフィクスチャを利用することができます。つまり、フィクスチャ名と同名の引数を取ってそのフィクスチャを発動させることができます(ただしスコープに矛盾がなければ――例えば、1つのテストの前後で出して片付ける花瓶をつかって、1ファイル内のすべてのテスト中ずっと薔薇を生けておくことはできません)。

import pytest

@pytest.fixture
def kabin():
    print('花瓶を用意します')
    yield []
    print('花瓶を片付けます')

@pytest.fixture  # @pytest.fixture(scope='module') とすると ScopeMismatch エラー
def bara_wo_iketa_kabin(kabin):
    print('花瓶に薔薇を生けます')
    kabin.append('薔薇')
    yield kabin
    print('花瓶から薔薇を取り除きます')

def test_1(bara_wo_iketa_kabin):
    print('テストします')
    assert bara_wo_iketa_kabin == ['薔薇']
$ pipenv run pytest -s
花瓶を用意します
花瓶に薔薇を生けます
テストします
花瓶から薔薇を取り除きます
花瓶を片付けます