採点されません。匿名です。 間違えることは学習の一部です。読むだけでもかまいません。

L?? ch02 — pytest fixture

テクノロジ系 / L10 test — テスト

L?? ch02 — pytest fixture

テストの「準備」を関数化して、毎回書かない・壊れにくくする

ゴール

  • @pytest.fixture で「テスト前の準備」を共通化できる
  • テスト関数の引数名 = fixture 名 で受け取れる
  • scope の違い (function / module) を最低限知っている

なぜ fixture か (Before)

def test_user_name():
    user = {"name": "Taro", "age": 30}  # 準備
    assert user["name"] == "Taro"

def test_user_age():
    user = {"name": "Taro", "age": 30}  # ← 同じ準備をまた書く
    assert user["age"] == 30

「準備」がコピペになり、データ変更で 複数箇所を直す ことに。

After (fixture でまとめる)

import pytest

@pytest.fixture
def user():
    return {"name": "Taro", "age": 30}

def test_user_name(user):       # 引数名 = fixture 名
    assert user["name"] == "Taro"

def test_user_age(user):
    assert user["age"] == 30

userテストごとに毎回呼ばれる (= 独立した状態)。

fixture の最小ルール

ルール内容
1@pytest.fixture を付けた関数を作る
2テスト関数の 引数名 に fixture 名を書く
3return した値が、その引数として渡される
4fixture は fixture を引数に取れる (連鎖)

fixture の連鎖

@pytest.fixture
def base_user():
    return {"name": "Taro"}

@pytest.fixture
def admin_user(base_user):
    return {**base_user, "role": "admin"}

def test_admin(admin_user):
    assert admin_user["role"] == "admin"
    assert admin_user["name"] == "Taro"   # base から継承

scope の違い

@pytest.fixture                    # 既定 = function (テストごと)
def fresh_user():
    return {"count": 0}

@pytest.fixture(scope="module")    # モジュール単位で 1 回だけ
def db_connection():
    return connect_db()            # 重い処理を共有
  • function (既定): 安全。テスト独立。
  • module: 速い。状態共有に注意 (テスト順依存になりがち)。

後片付け (yield)

@pytest.fixture
def temp_file(tmp_path):
    f = tmp_path / "data.txt"
    f.write_text("hello")
    yield f          # ← ここまでが「準備」
    # ↓ テスト後に実行される (= 後片付け)
    if f.exists():
        f.unlink()

return の代わりに yield を使うと、テスト後処理が書ける。

よくある間違い

# ❌ fixture を「関数呼び出し」してしまう
def test_user():
    u = user()        # → fixture は直接呼べない (pytest が injection する)

# ❌ 引数名が fixture 名と違う
def test_user(usr):   # → fixture "usr" が無い と怒られる
    ...

# ❌ fixture 内で global を書き換える
@pytest.fixture
def bad():
    global COUNTER     # → テスト間で状態漏れる

drill

drill/user fixture を完成させて、テストを PASS させる

拡張課題

  1. conftest.py に切り出す: 複数テストファイルで使う fixture は conftest.py に置けば import 不要で共有される
  2. parametrize と組み合わせる: @pytest.mark.parametrize でテストデータを増やしつつ fixture で前処理
  3. FastAPI の TestClient を fixture 化: client fixture を作っておくと、各エンドポイントテストが 1 行で書ける
   @pytest.fixture
   def client():
       from fastapi.testclient import TestClient
       from app.main import app
       return TestClient(app)
   

よくある詰まり

症状原因対処
fixture 'xxx' not found引数名と fixture 名が不一致スペルを揃える
テストごとに値が変わらないscope="module" で状態が漏れているscope を function に戻す
yield の後が実行されないテスト中に例外が出ても後処理は走るのが正しい挙動。走らないなら fixture の登録漏れ@pytest.fixture を付けたか確認

次に学ぶ領域

領域続けて読む
FastAPI の TestClienttest/ch03-testclient (次 chapter)
conftest.py での共有pytest 公式 docs
モック (unittest.mock)test/ch04-mock (将来)
力試ししたい方は クイズ形式の演習(任意) もあります。読むだけでも十分です。