【Python】テストの意図を明確にする「必要十分なテストデータ」の作り方

factory-boyのようなツールを使うと、テストデータの準備は非常に簡単になります。しかし、強力なツールを手にしたからといって、無計画にデータを作成してはなりません。テストの品質は、そのテストが**「何を検証しようとしているのか」**がどれだけ明確であるかに大きく依存します。

そして、その意図を最も明確に表現するのが、テストのために準備される**「データ」**そのものです。

今回のテーマは、**「テストのノイズを減らし、シグナルを強める」**ためのデータ準備の原則です。つまり、検証したい内容に直接関係する「必要十分」なデータだけを用意することで、テストの可読性と信頼性をいかに向上させるかを解説します。

目次

問題点:「ノイズ」が多く、意図が不明瞭なテストデータ

あるECサイトの商品検索機能search_productsをテストするシナリオを考えてみましょう。この関数は、検索語に加えて、オプションでカテゴリによる絞り込みも可能です。

悪い例:テストの関心事と無関係なデータ(ノイズ)が多い

# tests/test_search.py
from .factories import CategoryFactory, ProductFactory
from .search import search_products

def test_search_by_keyword():
    # Arrange:
    # このテストはキーワード検索を検証したいだけなのに、
    # カテゴリ名まで細かく指定しているのはノイズ
    category = CategoryFactory(name="PC周辺機器")
    product1 = ProductFactory(name="静音ワイヤレスマウス", category=category)
    # このテストでは使われない商品データも作られている
    product2 = ProductFactory(name="4Kモニター", category=category) 

    # Act
    results = search_products(term="マウス")

    # Assert
    # 1件見つかることはわかるが、なぜproduct2が除外されたかは自明ではない
    assert len(results) == 1
    assert results[0] == product1

このテストの問題点は、その**「ノイズの多さ」**にあります。

  • 意図の不明瞭さ: このテストの目的は「”マウス”という単語で検索できること」のはずです。しかし、セットアップコードにはcategory"4Kモニター"といった、この目的とは直接関係のない情報が含まれており、テストの核心(シグナル)が何なのかが分かりにくくなっています。
  • 検証の甘さ: このテストは、1件だけ正しく見つかるケースしか検証していません。「マウス」という単語を含む商品が複数あった場合に、それらすべてを正しく見つけ出せるかは保証されていません。

解決策:「必要十分」なデータでテストの物語を語る

優れたテストは、その準備データを通じて「何を検証したいのか」という物語を明確に語ります。

ケース1:キーワード検索のテスト

キーワード検索をテストするなら、必要なデータは「キーワードを含む商品」「含まない商品」そして「キーワードを複数含む商品」です。

良い例:テストの意図に合わせてデータを厳選

def test_search_by_keyword():
    # Arrange: 各データが明確な役割を持つ
    product_to_find_1 = ProductFactory(name="静音ワイヤレスマウス")
    product_to_find_2 = ProductFactory(description="高性能なゲーミングマウスです。")
    product_to_ignore = ProductFactory(name="メカニカルキーボード")

    # Act
    results = search_products(term="マウス")

    # Assert: 期待する2件が漏れなく、かつ余計な1件が含まれないことを検証
    assert len(results) == 2
    # 順序を問わないようにsetで比較するのが堅牢
    assert set(results) == {product_to_find_1, product_to_find_2}

このテストは、変数名 (_to_find, _to_ignore) とデータの作り方によって、その意図を明確に物語っています。また、複数件ヒットするケースを検証することで、テストの信頼性も向上しています。

ケース2:キーワード+カテゴリ検索のテスト

カテゴリによる絞り込みをテストするなら、必要なデータは「キーワードとカテゴリが両方一致する商品」「キーワードは一致するがカテゴリが違う商品」「カテゴリは一致するがキーワードが違う商品」です。

良い例:条件の組み合わせを検証するためにデータを設計

def test_search_by_keyword_and_category():
    # Arrange:
    # factory-boyの `__` 記法で関連モデルの属性も簡潔に指定
    product_to_find = ProductFactory(name="多機能マウス", category__name="PCアクセサリ")
    product_to_ignore1 = ProductFactory(name="ワイヤレスマウス", category__name="オーディオ機器")
    product_to_ignore2 = ProductFactory(name="トラックボール", category__name="PCアクセサリ")

    # Act
    results = search_products(term="マウス", category_name="PCアクセサリ")

    # Assert
    assert len(results) == 1
    assert results[0] == product_to_find

このテストデータは、「”PCアクセサリ” カテゴリの “マウス”」という条件を検証するために、必要最小限かつ十分な対照群を用意しており、テストのロジックが非常に明確です。

まとめ

テストの品質を高めるためのデータ準備の指針は以下の通りです。

  1. ノイズをなくす: テストの検証内容と無関係なデータや属性の指定をやめる。
  2. シグナルを強める: 検証したい振る舞いに直接関わるデータは、ファクトリの引数で明示的に指定する。
  3. 対照実験を行う: 条件に「一致するデータ」と「一致しないデータ」の両方を用意し、フィルタリングが正しく機能することを保証する。
  4. 複数件をテストする: 複数件の結果が返りうる機能では、実際に複数件のマッチングデータを用意して検証する。

テストデータは単なる「準備」ではありません。それは、テストの意図と仕様を伝えるための最も雄弁な「物語」なのです。

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

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次