この記事のポイント

  • pytestのfixture設計臭をレビュー視点で読み解ける
  • スコープ管理と依存整理技法を学べる
  • fixture肥大化を抑止する実務設計文化を体系化できる
  • PlantUMLでfixture依存構造の整理イメージを可視化できる

そもそもpytestのfixtureとは

pytestのfixtureは「事前準備(前処理)を再利用可能な注入構造に分離する仕組み」です。
unittestのsetUp()より柔軟に

  • スコープ制御(function/module/session)
  • 依存注入(fixtureからfixtureを呼ぶ)
  • パラメータ化(parametrize対応)
  • yield構文で後処理統合

が行えます。

pytest fixture基本例

import pytest

@pytest.fixture
def db():
    return MockDatabase()

def test_insert(db):
    db.insert("alice")
    assert db.count() == 1
  • テスト関数は引数にfixture名を書く
  • pytestが自動注入・実行順序制御

なぜこれをレビューするのか

pytest fixtureは「最初は便利、後に肥大崩壊しやすい」特性を持ちます。
レビューアーは以下を観察する責任を持ちます。

レビューアー視点

  • fixture定義が機能単位で整理されているか
  • fixture間の依存連鎖が破綻していないか
  • スコープ指定が適切に使い分けられているか
  • 不要共有(sessionスコープ濫用)が発生していないか
  • fixture読解コストが抑えられているか

開発者視点

  • fixture依存注入の自由度に油断
  • 便利だからfixtureに全部詰め込みがち
  • yield前後処理を無意識に積み上げ
  • sessionスコープを多用して副作用温床化

fixture崩壊の典型設計臭

崩壊しやすいパターン
  • fixtureの中でさらにfixture呼出が連鎖
  • データ生成も副作用処理も全てfixture混入
  • fixture一個作ると全テストで使いたくなる欲求
  • スコープ指定の場当たり適用
  • fixtureファイル1個に全部集中肥大

崩壊例:依存連鎖肥大型

依存連鎖例

@pytest.fixture
def db():
    return MockDatabase()

@pytest.fixture
def user(db):
    db.insert_user("alice")
    return "alice"

@pytest.fixture
def order(user, db):
    db.insert_order(user, "item123")
    return "order123"

def test_order(order):
    assert order == "order123"
@Reviewer
fixture依存連鎖が進行し読解難度が高まっています。生成責務を個別テスト内に戻す整理も検討してください。

問題点

  • fixture層が階層深く可視性低下
  • 依存先修正で波及リスク高

崩壊構造モデル:fixture依存肥大構造

UML Diagram

fixture整理の設計原則

pytest fixture設計は以下の整理文化が有効です。

① 機能別分割文化

  • DB接続 fixture
  • 外部API fixture
  • ドメイン生成 fixture(必要最小限)

② 最小依存文化

  • fixture → fixture 呼出は最小限に抑制

③ スコープ意識文化

スコープ 主用途 使い過ぎ注意
function 通常使用
module APIレスポンスキャッシュ
session DB準備キャッシュ ×過剰厳禁

④ 明示命名文化

  • fixture名は機能語彙優先
  • db → db_connection 等

⑤ 副作用封じ文化

  • fixture内データ生成責務は原則テスト本体に戻す優先

改善例:依存分離整理

改善整理版

@pytest.fixture
def db_connection():
    return MockDatabase()

def create_user(db, username):
    db.insert_user(username)
    return username

def create_order(db, username, item):
    db.insert_order(username, item)
    return item

def test_order(db_connection):
    user = create_user(db_connection, "alice")
    order = create_order(db_connection, user, "item123")
    assert order == "item123"
「fixtureは環境を用意、データはテストで用意文化」

レビューアーはfixtureとデータ生成の分離文化を推進すると保守性が激変します。

改善構造モデル:責務分離整理

UML Diagram

良くない実装例: ケース1(スコープ肥大)

session濫用例

@pytest.fixture(scope="session")
def db():
    db = MockDatabase()
    yield db
    db.close()
@Reviewer
sessionスコープで全テスト共有されています。副作用制御困難化します。functionスコープ優先に戻してください。

問題点

  • テスト独立性崩壊
  • 並列実行破綻

良くない実装例: ケース2(fixture多層呼出)

fixture呼出例

@pytest.fixture
def user(db):
    db.insert_user("alice")
    return "alice"

@pytest.fixture
def order(user, db):
    db.insert_order(user, "item123")
    return "order123"
@Reviewer
fixtureからfixture呼出が連鎖しています。依存整理を優先してください。

問題点

  • fixture依存経路肥大化
  • 読解負荷上昇

改善例:依存注入分離版

改善版

@pytest.fixture
def db():
    return MockDatabase()

def test_order(db):
    user = "alice"
    db.insert_user(user)
    db.insert_order(user, "item123")
    assert db.count_order(user) == 1
  • fixtureは純粋環境提供
  • データ生成はテスト内で直列化

観点チェックリスト

まとめ

pytest fixture設計は「再利用文化と肥大文化の表裏一体」です。
レビューアーは「fixture分離文化・依存最小文化・データ生成分離文化」を育成指導することで、長期保守に耐えるpytest設計を維持できます。