Pythonテストフレームワーク「pytest」でテストコードを書く【完全ガイド】
はじめまして、まつのです!
機械学習や生成AIの受託開発・AI学習サービス「aipass」の運営をしている株式会社dotConfという会社で、代表をしております!

この記事では、Pythonのテストフレームワーク「pytest」について実装方法をわかりやすく解説します。
pytestとは?
pytestとは、Pythonでユニットテストを書くためのフレームワークです。他にも様々なユニットテスト用のフレームワークはありますが、文法がシンプルで分かりやすいためpytestを使うことをお勧めします。
環境構築
まずは以下を実行して pytest と pytest-cov をインストールします。
pip install pytest pytest-cov
テストコードを書いてみる
まずはユニットテストの対象となるソースコードを準備します。ここでは四則演算を行う関数を対象とします。
def add(a, b):
return a + b
def sub(a, b):
return a - b
def mul(a, b):
return a * b
def div(a, b):
if b == 0:
raise ValueError("division by zero")
return a / b
続いてこれらの関数に対してテストコードをpytestで書いてみます。
from calc import add, sub, mul, div
import pytest
def test_add():
assert add(2, 3) == 5
def test_sub():
assert sub(5, 3) == 2
def test_mul():
assert mul(2, 4) == 8
def test_div():
assert div(10, 2) == 5
def test_div_zero():
with pytest.raises(ValueError):
div(10, 0)
テストを実行します
pytest -v
================== test session starts ==================
collected 5 items
test_calc.py::test_add PASSED [ 20%]
test_calc.py::test_sub PASSED [ 40%]
test_calc.py::test_mul PASSED [ 60%]
test_calc.py::test_div PASSED [ 80%]
test_calc.py::test_div_zero PASSED [100%]
=================== 5 passed in 0.03s ====================
結果を見てみると全ての関数で「PASSED」となっており、全て期待通りに実装できていることがわかります。
ここであえてバグのある関数pow()とそれに対するテストコードtest_pow()を追加してみます。pow()はべき乗を計算する関数のつもりが、掛け算になっているというバグにしておきます。
def add(a, b):
return a + b
def sub(a, b):
return a - b
def mul(a, b):
return a * b
def div(a, b):
if b == 0:
raise ValueError("division by zero")
return a / b
def pow(a,b):
# 正しくは、a**b
return a * b
from calc import add, sub, mul, div, pow
import pytest
def test_add():
assert add(2, 3) == 5
def test_sub():
assert sub(5, 3) == 2
def test_mul():
assert mul(2, 4) == 8
def test_div():
assert div(10, 2) == 5
def test_div_zero():
with pytest.raises(ValueError):
div(10, 0)
def test_pow():
# 追加したテストコード
assert pow(3, 2) == 9
テストを実行してみます。
pytest -v
================== test session starts ==============
collected 6 items
test_calc.py::test_add PASSED [ 16%]
test_calc.py::test_sub PASSED [ 33%]
test_calc.py::test_mul PASSED [ 50%]
test_calc.py::test_div PASSED [ 66%]
test_calc.py::test_div_zero PASSED [ 83%]
test_calc.py::test_pow FAILED [100%]
====================== FAILURES ======================
______________________ test_pow ______________________
def test_pow():
# 追加したテストコード
> assert pow(3, 2) == 9
E assert 6 == 9
E + where 6 = pow(3, 2)
test_calc.py:22: AssertionError
=============== short test summary info ===============
FAILED test_calc.py::test_pow - assert 6 == 9
=============== 1 failed, 5 passed in 0.05s ============
test_powは「FAILED」となっており、バグをテストで検知することができました。
パラメータテスト
同じ関数を複数パターンで検証したい場合、@pytest.mark.parametrizeを使います。
テスト関数を1つ書くだけで、複数の入力・期待値を自動でテストできます。ここでは先ほど作成した足し算を行うadd関数に対するパラメータテストを書いてみます。
import pytest
from calc import add
@pytest.mark.parametrize(
"a,b,expected",
[
(1, 2, 3),
(0, 0, 0),
(-1, 1, 0),
(100, 200, 300),
],
ids=["1+2", "0+0", "-1+1", "100+200"]
)
def test_add_param(a, b, expected):
assert add(a, b) == expected
パラメータテストを実行します。
pytest -v -k "add_param"
================== test session starts ==================
collected 6 items
test_calc.py::test_add_param[1+2] PASSED [ 25%]
test_calc.py::test_add_param[0+0] PASSED [ 50%]
test_calc.py::test_add_param[-1+1] PASSED [ 75%]
test_calc.py::test_add_param[100+200] PASSED [100%]
=================== 4 passed in 0.02s ====================
テストカバレッジ
テストされていない関数があるとバグの元となるため、実装したすべての関数はテストを実施する必要があります。pytest-covを利用するとテストコードがない関数やその割合を炙り出すことができます。
pytest --cov=calc -q
---------- coverage: platform linux, python 3.10 ----------
Name Stmts Miss Cover
-----------------------------
calc.py 12 0 100%
-----------------------------
TOTAL 12 0 100%
| 項目 | 意味 |
|---|---|
| Name | 測定対象のファイル名 |
| Stmts | ステートメント(statement)の数=実行可能なコード行数 |
| Miss | テスト中に実行されなかった行数 |
| Cover | カバレッジ(= 100 × (Stmts - Miss) / Stmts )=網羅率 |
test_calc.pyからtest_pow()を削除してみましょう。
from calc import add, sub, mul, div
import pytest
def test_add():
assert add(2, 3) == 5
def test_sub():
assert sub(5, 3) == 2
def test_mul():
assert mul(2, 4) == 8
def test_div():
assert div(10, 2) == 5
def test_div_zero():
with pytest.raises(ValueError):
div(10, 0)
""" 削除
def test_pow():
# 追加したテストコード
assert pow(3, 2) == 9
"""
再度カバレッジテストを実行すると、以下のようにテストコードが未実装の関数があることがわかります。
---------- coverage: platform linux, python 3.10 ----------
Name Stmts Miss Cover
-----------------------------
calc.py 12 1 92%
-----------------------------
TOTAL 12 1 92%
まとめ
pytest は「シンプルだけど強力」なテストフレームワークです。assertで直感的に書け、parametrizeで効率的に検証し、pytest-covで品質を可視化できます。
Pythonを学習したい方へ
Pythonを体系的に学び、プロの指導のもとで実践的なAIスキルを習得したい方、
キャリアの幅を広げたい方や複業を目指す方は、ぜひこちらからお問い合わせください。
Discussion