はじめてのpytest

Author

Ryo Nakagami

Published

2024-11-11

Modified

2024-12-24

なぜpytestを使うのか?

Pythonが提供するユニットテストフレームワークとして, unittestがありますが,unittestと比べpytestは以下のようなメリットがあります.

  • command-line tool
  • Classは必要に応じて作成すれば良く,小規模なテストについてはテスト関数の定義のみで十分
  • assert 文がシンプル
  • traceback機能が充実しており,また不必要ならばoffすることができる

assert

pytestを用いたunit testの基本構文を理解するために以下のコードを見てみます.

def test_passing():
    assert (1, 2, 3) == (1, 2, 3)

assert文はテストの成否を判断するPythonの組み込みコマンドです.assert以下がFalseと評価されると,AssertionErrorを発生させます.

test_passingという関数の名前はtest_から始まってますが,pytesttest_で始まる関数をテスト関数として検出しテストを実行します.

Example 1 : test_script_001.py

def test_passing():
    assert (1, 2, 3) == (1, 2, 3)


def test_passing2():
    assert (2, 3, 4) == (2, 3, 4)


def nottest_passing():
    assert (1, 2, 3) == (1, 2, 3)

というpytest用のファイルを用意します.これを実行すると

pytest -v ./pytest_scripts/test_script_001.py
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.12.8/x64/bin/pytest", line 5, in <module>
    from pytest import console_main
ModuleNotFoundError: No module named 'pytest'

上記の例では,

  • collecting ... collected 2 itemsよりテスト関数が2つ検出された
  • test_passing, test_passing2 が問題なくテストパスした

という情報が表示されています.

▶  テストが失敗する場合

def test_failing():
    assert (1, 2) == (1, 1)

という関数を準備し,あえて失敗させてみます.

pytest -v ./pytest_scripts/test_script_002.py
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.12.8/x64/bin/pytest", line 5, in <module>
    from pytest import console_main
ModuleNotFoundError: No module named 'pytest'

At index 1 diff: 2 != 1 とあるように index 1が一致していないと教えてくれます.pytestが表示するテストが失敗した場所とその周囲のコードのセクションのことをトレースバック(traceback)と呼びます.これの表示をoffにしたい場合は

pytest --tb=no ./pytest_scripts/
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.12.8/x64/bin/pytest", line 5, in <module>
    from pytest import console_main
ModuleNotFoundError: No module named 'pytest'

Pytest assert

pytestが利用するassertはPythonの組み込みstatementと同じですが,unittestなどの他のフレームワークのassertヘルパー関数と比べシンプルに利用することができます. 例として,

pytest unittest
assert something assertTrue(something)
assert a == b assertEqual(a, b)
assert a != b assertNotEqual(a, b)
assert a <= b assertLessEual(a, b)
assert a is None assertIsNone(a)
assert a is not None assertIsNotNone(a)

テスト結果

pytest_scripts/test_script_001.py ..                                     [ 66%]
pytest_scripts/test_script_002.py F                                      [100%]

に着目すると .., F といった文字列が確認できます.これはpytestのテスト結果を表しています.

結果 表示 説明
PASSED . 正常に実行された個数を.の個数で示す
FAILED F 正常に実行されなかった個数をFの個数で示す
SKIPPED s スキップされたテストを示す
XFAIL x 想定通り失敗したテストを示す.@pytest.mark.xfail()pytestに教える
XPASS X xfailマーカーを設定したのに成功したテストを示す
ERROR E 例外が想定通り発生したことを示す