pytestのparametrizeでidを指定できる(test ID)

pytestにはtest IDという機能があります。 この機能を使うことで、テストの実行結果をちょっとわかりやすくできます。

今回は以下の環境で確認しました。

  • Python3.12.1
  • pytest 8.2.2

pytestの公式リファレンスでは以下に例が記載されています。

https://docs.pytest.org/en/8.2.x/example/parametrize.html#set-marks-or-test-id-for-individual-parametrized-test

具体例

まず、以下のような成績を算出するメソッドを作成します。

def grade(score: int) -> str:
    """採点を行う

    0点-59点: 不可
    60点-69点: 可
    70点-79点: 良
    80点-100点: 優
    """
    if score < 60:
        return "不可"
    elif score < 70:
        return "可"
    elif score < 80:
        return "良"
    else:
        return "優"

次に、このメソッドをテストするためのテストケースを作成します。

from grade import grade

import pytest

@pytest.mark.parametrize('scode,expected', [
    (50, '不可'),
    (60, '可'),
    (70, '良'),
    (80, '優'),
])
def test_grade(scode, expected):
    assert grade(scode) == expected

このテストケースを引数-v付きで実行すると、以下のような結果が得られます。

================================================================================================================================================ 4 passed in 0.01s ================================================================================================================================================
(venv) tatsuya: pytest-parametrized/ % pytest -v                                                                                                                                                                                                                                                      (git)-[main]
=============================================================================================================================================== test session starts ===============================================================================================================================================
platform darwin -- Python 3.12.1, pytest-8.2.2, pluggy-1.5.0 -- /Users/tatsuya/sandbox/pytest-freezer/venv/bin/python3.12
cachedir: .pytest_cache
rootdir: /Users/tatsuya/sandbox/pytest-parametrized
configfile: pytest.ini
plugins: pytest_freezer-0.4.8
collected 4 items                                                                                                                                                                                                                                                                                                 

test_parametrized_test_id.py::test_grade[50-\u4e0d\u53ef] PASSED                                                                                                                                                                                                                                            [ 25%]
test_parametrized_test_id.py::test_grade[60-\u53ef] PASSED                                                                                                                                                                                                                                                  [ 50%]
test_parametrized_test_id.py::test_grade[70-\u826f] PASSED                                                                                                                                                                                                                                                  [ 75%]
test_parametrized_test_id.py::test_grade[80-\u512a] PASSED           

================================================================================================================================================ 4 passed in 0.01s ================================================================================================================================================

テストがすべて成功しているのはわかりますが、名前が自動でpytest.paramから取得されているため、ちょっとわかりにくいです。[50-\u4e0d\u53ef]のようになっています。

(今回のケースだと期待値が日本語のためUnicodeエスケープシーケンスで表示されている、と言うのもありますが)

そこで、idを利用します。例として、id="param-50-Poorのようにします。

from grade import grade

import pytest

@pytest.mark.parametrize('score,expected', [
    pytest.param(50, "不可", id="param-50-Poor"),
    pytest.param(60, "可", id="param-60-Average"),
    pytest.param(70, "良", id="param-70-Good"),
    pytest.param(80, "優", id="param-80-Excellent"),
])
def test_grade(score, expected):
    assert grade(score) == expected

すると、以下のようになり個人的には実行前よりわかりやすくなると感じました。

test_parametrized_test_id.py::test_grade[param-50-Poor] PASSED                                                                                                                                                                                                                                              [ 25%]
test_parametrized_test_id.py::test_grade[param-60-Average] PASSED                                                                                                                                                                                                                                           [ 50%]
test_parametrized_test_id.py::test_grade[param-70-Good] PASSED                                                                                                                                                                                                                                              [ 75%]
test_parametrized_test_id.py::test_grade[param-80-Excellent] PASSED  

また、#で「こういうテスト」と書かずにそのまま個別のテスト名としても書けるので、テスト実行如何に関わらず、ちょっと読みやすくなるかな?とも思っています。 実際には-vを利用して毎回テストするかどうか、でいうと「毎回でも無いかな?デバッグの時がメインかな?」と言う気もするので。