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

pytestでパラメータ化する3つの方法を解説

【初心者】pytestでパラメータ化する3つの方法を解説
エソラ

この記事では、pytestで単純な足し算をする関数をパラメータ化して、テストする方法を解説します。

テストを書いていると、同じ処理を異なるデータで検証したい時があります。何も考えないと、似たコードが量産されますが、パラメータ化をすると解決できます。

パラメータ化すれば、短くシンプルなコードで、一つのテスト関数を複数のテストデータで検証できます。

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

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

この記事を読めば、pytestでパラメータテストをする方法・使い分けについて、バッチリ理解ができます。

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

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

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

目次

テスト関数をパラメータ化する

エソラ

テスト関数をパラメータ化する方法が最もスタンダードなやり方です。

テスト関数をパラメータ化するには、テスト関数の前に@pytest.mark.parametrizeを書きます。

引数にはそれぞれ、以下を設定します。

  • 第1引数:テスト関数で使う引数名
  • 第2関数:検証したい値のパラメータ(リスト型)

コードにすると以下のようになります。

import pytest


def addition(x, y):
    """
    足し算をして、返す
    """
    return x + y


@pytest.mark.parametrize(
    "x, y , result",
    [
        (1, 2, 3),
        (1, 2, 4),
        (10, 23, 33)
    ],
)
def test_addition(x, y, result):
    """
    関数をパラメータ化して、additionを検証
    """
    assert result == addition(x, y)

これをpytestで実行すると、以下のようになります。

$ pytest test_func_param.py 
================================================= test session starts ==================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 3 items                                                                                                      

test_func_param.py .F.                                                                                           [100%]

======================================================= FAILURES =======================================================
_________________________________________________ test_addition[1-2-4] _________________________________________________

x = 1, y = 2, result = 4

    @pytest.mark.parametrize(
        "x, y , result",
        [
            (1, 2, 3),
            (1, 2, 4),
            (10, 23, 33)
        ],
    )
    def test_addition(x, y, result):
>       assert result == addition(x, y)
E       assert 4 == 3
E        +  where 3 = addition(1, 2)

test_func_param.py:20: AssertionError
=============================================== short test summary info ================================================
FAILED test_func_param.py::test_addition[1-2-4] - assert 4 == 3
============================================= 1 failed, 2 passed in 0.14s ==============================================

2つ目のパラメータの足し算が間違っているため、2つ目のテストコードが失敗しているのが分かりますね。

fixtureをパラメータ化する

エソラ

テストで前処理、後処理を書く場合、fixtureが使えます。

fixtureの書き方が分からないなら、以下にまとめています。

fixtureをパラメータ化する時は、@pytest.fixtureの引数にパラメータを設定します。

fixtureのメソッドの引数(request)にパラメータが引き渡され、パラメータごとに検証する値を設定します。

テストコードにすると、以下の通りです。

import pytest


def addition(x, y):
    """
    足し算をして、返す
    """
    return x + y


@pytest.fixture(params=['a', 'b', 'c'])
def fix_param(request):
    """
    フィクスチャにパラメータを設定
    """
    if request.param == 'a':
        return (1, 2, 3)
    elif request.param == 'b':
        return (1, 2, 4)
    elif request.param == 'c':
        return (10, 23, 33)


def test_addition(fix_param):
    """
    フィクスチャをパラメータ化して、additionを検証
    """
    x, y, result = fix_param
    assert result == addition(x, y)

では、テストコードを実行してみましょう。

$ pytest test_fixture_param.py 
================================================= test session starts ==================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 3 items                                                                                                      

test_fixture_param.py .F.                                                                                        [100%]

======================================================= FAILURES =======================================================
___________________________________________________ test_addition[b] ___________________________________________________

fix_param = (1, 2, 4)

    def test_addition(fix_param):
        """
        フィクスチャをパラメータ化して、additionを検証
        """
        x, y, result = fix_param
>       assert result == addition(x, y)
E       assert 4 == 3
E        +  where 3 = addition(1, 2)

test_fixture_param.py:29: AssertionError
=============================================== short test summary info ================================================
FAILED test_fixture_param.py::test_addition[b] - assert 4 == 3
============================================= 1 failed, 2 passed in 0.06s ==============================================

テスト関数をパラメータ化した時と同様の結果になっていることが分かると思います。

fixtureをパラメータ化するメリット

エソラ

テスト関数と比べて、fixtureのパラメータ化は、コードが冗長になりますね。

fixtureをパラメータ化するメリットは、パラメータの値に基づいて、前処理、後処理ができることにあります。

fixtureをパラメータ化したら良いユースケースは以下の通り。

fixtureのパラメータ化のユースケース
  • 異なるデータベースに接続
  • 異なるファイルを読み込む
  • 同じデータセットで複数の関数のテストをする

fixtureを使うことで、前処理、後処理をまとめることができます。テスト関数のパラメータ化では、それぞれの関数にデータベース接続処理や、ファイルの読み込み処理を書く必要があり、コードが冗長になります。

ここに該当しない場合は、テスト関数をパラメータ化する方が、コードがシンプルになり、保守性が上がります。

エソラ

それぞれの書き方の使い所をしっかりと把握することが大切です。

フック関数(pytest_generate_tests)で、パラメータ化する

フック関数(pytest_generate_tests)を使って、パラメータ化することができます。

フック関数はpytestの通常の処理フローを変更するために、プラグインとして使うことができます。

テストコードを実装すると、以下の通り。

def addition(x, y):
    """
    足し算をして、返す
    """
    return x + y


def pytest_generate_tests(metafunc):
    if "param" in metafunc.fixturenames:
        metafunc.parametrize("param", [(1, 2, 3), (1, 2, 4), (10, 23, 33)])


def test_addition(param):
    """
    pytest_generate_testsを利用して、additionを検証
    """
    print(param)
    x, y, result = param
    assert result == addition(x, y)

では、テストコードを実行してみましょう。

$ pytest test_generate.py
======================================================== test session starts ========================================================
platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0
rootdir: (省略)
collected 3 items                                                                                                                   

test_generate.py .F.                                                                                                          [100%]

============================================================= FAILURES ==============================================================
_______________________________________________________ test_addition[param1] _______________________________________________________

param = (1, 2, 4)

    def test_addition(param):
        """
        pytest_generate_testsを利用して、additionを検証
        """
        print(param)
        x, y, result = param
>       assert result == addition(x, y)
E       assert 4 == 3
E        +  where 3 = addition(1, 2)

test_generate.py:19: AssertionError
------------------------------------------------------- Captured stdout call --------------------------------------------------------
(1, 2, 4)
====================================================== short test summary info ======================================================
FAILED test_generate.py::test_addition[param1] - assert 4 == 3
==================================================== 1 failed, 2 passed in 0.16s ====================================================

これまでと同じ結果になることが分かります。

複雑なパラメータセットを作成する場合、pytest_generate_testsは非常に強力です。

よくある質問

パラメータ化テストのメリットは?

パラメータ化テストのメリットは、複数のデータパターンをシンプルなコードで検証できることです。パラメータを使わないと、同じようなテスト関数を量産する必要があり、複雑性が増します。

いつパラメータ化テストをしたら良いですか?

if文の振る舞いや境界値テストでよく使います。

fixtureをパラメータ化するメリットは?

fixtureをパラメータ化することで、パラメータに応じた前処理・後処理をfixtureにまとめて書くことができます。ユースケースの例は、パラメータごとにデータベースに接続先を変える場合、ファイルの読み込みを変える場合などです。

pytest_generate_testsでパラメータ化するメリットは?

複雑なデータセットで検証したい時に使えます。

Python学習におすすめのコンテンツ

現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル

Udemyの講座でPythonなら、文句なしにおすすめ

現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル
総合評価
( 5 )
メリット
  • 分かりやすい言葉や具体的なコードで工夫して説明しているので、初心者でも理解できる。
  • 初心者でも挫折しないように、丁寧に詳しく手順を説明している。
  • 講座内で取り扱う課題は実践的なものが多く、書籍では身につかない応用力を身につけられる。
デメリット
  • 情報量が多いのに、講座の進み方が速いので、一回では理解が追いつかない。
  • 課題の難易度が高すぎる場合がある。
  • 講師のアクセントが特殊で、聞き取りにくいと感じたことがある。

テスト駆動Python 第2版

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

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

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

著:Brian Okken, 翻訳:株式会社クイープ, 監修:株式会社クイープ, 監修:安井 力
¥3,234 (2024/04/26 12:24時点 | Amazon調べ)

とても便利なpytestのパラメータ化

ここまで、pytestをパラメータ化する方法について解説しました。

復習すると、パラメータ化の方法は3つありました。

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

上記の通り、それぞれの方法について、明確な使い時があります。

書きたいテストコードに応じて、書き方を変えるとシンプルで高度なテストができます。

pytestでテストコードが書ければ、複数のデータパターンでテストができます。品質の高いプログラムを開発できて、現場でも重宝されます。

エソラ

一度、使い方を理解すれば簡単に使えて、とても便利。自分の市場価値を高めるためにも、pytestをマスターして、スキルアップして欲しいと思います。

著:Brian Okken, 翻訳:株式会社クイープ, 監修:株式会社クイープ, 監修:安井 力
¥3,234 (2024/04/26 12:24時点 | Amazon調べ)

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

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

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

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

エソラ

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

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

エソラ

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

【初心者】pytestでパラメータ化する3つの方法を解説

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

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

コメント

コメントする

目次