JavaScriptを有効にしてください

pytestを使ったPythonのテスト

 ·   4 min read

※記事内に商品プロモーションを含むことがあります。

はじめに

pytestによる基本的なテストの実行方法と、複数のテストケースを記述する方法を解説します。

環境は以下の通りです。

  • OS: Windows 10 Home
  • Python 3.9.18
  • pytest 7.4.0

pytestの基本的な使い方

まず、以下のPythonスクリプトfoo.pyを作成します。

1
2
3
4
5
def add(x, y):
    return x+y

def test_add():
    assert add(1, 2) == 3

add()がテスト対象となる関数です。
また、test_add()はpytestでテストするための関数です。pytestでは、testから始まる関数を対象にテストを実行します。assert文の後ろに、Trueになると期待される(=テスト結果として正しい)判定式を記述します。

次に、Powershellなどのコマンドラインで以下を実行します。pytestの引数としてスクリプト名を与えます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> pytest foo.py
======================= test session starts =======================
platform win32 -- Python 3.9.18, pytest-7.4.0, pluggy-1.0.0
rootdir: D:\document\Python Scripts\pytest
plugins: anyio-3.5.0
collected 1 item

foo.py .                                                     [100%]

======================== 1 passed in 0.04s ========================

X passedとのみ表示されている場合、テストに成功しています。

テストに失敗した場合の挙動

次に、add()関数にバグがあった場合の挙動を確認します。バグがあるスクリプトfoo2.pyを作成し、同じようにpytestを実行します。

1
2
3
4
5
def add(x, y):
    return x+y+1

def test_add():
    assert add(1, 2) == 3
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
> pytest foo2.py
======================= test session starts =======================
platform win32 -- Python 3.9.18, pytest-7.4.0, pluggy-1.0.0
rootdir: D:\document\Python Scripts\pytest
plugins: anyio-3.5.0
collected 1 item

foo2.py F                                                    [100%]

============================ FAILURES =============================
____________________________ test_add _____________________________

    def test_add():
>       assert add(1, 2) == 3
E       assert 4 == 3
E        +  where 4 = add(1, 2)

foo2.py:5: AssertionError
===================== short test summary info =====================
FAILED foo2.py::test_add - assert 4 == 3
======================== 1 failed in 0.23s ========================

テスト結果に間違いがある場合、このようにFAILURESと出力されます。

ファイルを分割する

プログラムの量が増えてくると、テスト対象となるファイルと、pytestでテストを実行するためのファイルを分割したくなります。
前者をfoo3.py, 後者をtest_foo3.pyとして、以下のように作成して同じフォルダに置きます(別のフォルダに置く方法もあります)。

1
2
def add(x, y):
    return x+y
1
2
3
4
from foo3 import add

def test_add():
    assert add(1, 2) == 3

なお、テストを実行するためのプログラムのファイル名はtest_*.pyまたは*_test.pyとします。

foo3.pytest_foo3.pyがあるディレクトリで、引数を付けずにpytestコマンドを実行するとテストが実行されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> pytest
======================= test session starts =======================
platform win32 -- Python 3.9.18, pytest-7.4.0, pluggy-1.0.0
rootdir: D:\document\Python Scripts\pytest
plugins: anyio-3.5.0
collected 1 item

test_foo3.py .                                               [100%]

======================== 1 passed in 0.05s ========================

複数ケースでテストする

ある関数に対して、通常は複数の入力値を与えてテストをすると思います。pytest上の書き方はいくつかあります。

  • テスト用関数を複数定義する
  • 1つのテスト用関数の中で複数回テストする
  • pytest.mark.parametrizeを使う

テスト用関数を複数定義

以下のようにテスト用関数を複数定義します。関数名の末尾に連番を振っていますが、pytestの仕様では必須ではありません。もし途中のテストに失敗した場合でも、最後の関数までテストは実行されます。なお、以下の例では、テストケース数は3としてカウントされます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def add(x, y):
    return x+y

def test_add_01():
    assert add(1, 2) == 3

def test_add_02():
    assert add(2, 3) == 3

def test_add_03():
    assert add(3, 4) == 7
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> pytest foo4.py
======================= test session starts ========================
platform win32 -- Python 3.9.18, pytest-7.4.0, pluggy-1.0.0
rootdir: D:\document\Python Scripts\pytest
plugins: anyio-3.5.0
collected 3 items

foo4.py ...                                                   [100%]

======================== 3 passed in 0.04s =========================

1つのテスト用関数の中で複数回テスト

以下のように1つのテスト用関数test_add()の中に複数のassert文を書いた場合でも、複数回のテストは可能です。しかし、途中のassert文のテスト結果が正しくなかった場合、同じ関数にあるそれ以降のassert文は評価されません。例えば、add(1, 2) == 3の評価結果が正しくなかった場合、add(2, 3) == 4add(3, 4) == 7は評価されません。なお、以下の例では、テストケース数は1としてカウントされます。

1
2
3
4
5
6
7
def add(x, y):
    return x+y

def test_add():
    assert add(1, 2) == 3
    assert add(2, 3) == 4
    assert add(3, 4) == 7
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> pytest foo5.py
======================= test session starts ========================
platform win32 -- Python 3.9.18, pytest-7.4.0, pluggy-1.0.0
rootdir: D:\document\Python Scripts\pytest
plugins: anyio-3.5.0
collected 1 item

foo5.py .                                                     [100%]

======================== 1 passed in 0.05s =========================

pytest.mark.parametrizeを使う

pytestをインポートし、テスト用関数の前にデコレータ@pytest.mark.parametrizeを追加します。デコレータは、関数を装飾するPythonの機能です。デコレータの第1引数として、"a, b, c"のように関数の引数を文字列で与えます。第2引数には、テストケースごとの引数のタプルをリストで与えます。このデコレータを使用すると、途中で失敗しても最後のテストケースまで実行します。なお、以下の例では、テストケース数は3としてカウントされます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pytest

def add(x, y):
    return x+y

@pytest.mark.parametrize("a, b, c", [
    (1, 2, 3),
    (2, 3, 5),
    (3, 4, 7)
])
def test_add(a, b, c):
    assert add(a, b) == c
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
> pytest foo6.py
======================= test session starts ========================
platform win32 -- Python 3.9.18, pytest-7.4.0, pluggy-1.0.0
rootdir: D:\document\Python Scripts\pytest
plugins: anyio-3.5.0
collected 3 items

foo6.py ...                                                   [100%]

======================== 3 passed in 0.05s =========================

参考

シェアする

Helve
WRITTEN BY
Helve
関西在住、電機メーカ勤務のエンジニア。X(旧Twitter)で新着記事を配信中です

サイト内検索