Web APIのエンドポイントを作ったときにpytestを使うことが増えたので、実際によく使うものだけ自分用に整理しておく。以前のメモにはコマンドのタイプミスやfixture scopeの考え方で誤解しやすい部分があったので、2026年9月時点で書き直した。
インストール
python -m pip install pytest
coverageも見る場合はpytest-covも入れる。
python -m pip install pytest pytest-cov
まず使うコマンド
プロジェクトルートから実行する。
# 全テスト
pytest
# 詳細表示
pytest -v
# ファイル指定
pytest tests/test_routes.py
# 関数指定
pytest tests/test_routes.py::test_login
# クラス内のテスト指定
pytest tests/test_routes.py::TestAuth::test_login
# 名前で絞り込み
pytest -k "login"
# 最初の失敗で止める
pytest -x
# 2件失敗したら止める
pytest --maxfail=2
# print()をそのまま表示
pytest -s
以前のメモにあったputestは単純なタイプミス。正しくはpytest。
テストファイルの命名
pytestは標準ではtest_*.pyまたは*_test.pyのファイルを収集する。テスト関数はtest_で始める。
# tests/test_calc.py
def test_add():
assert 1 + 2 == 3
conftest.py
複数のテストで共通利用するfixtureはconftest.pyに置くことが多い。テスト側で通常のimportは不要。pytestが対象テストのディレクトリと親ディレクトリ側のconftest.pyを見つけて読み込む。
tests/
├── conftest.py
├── test_auth.py
└── test_users.py
fixtureの基本
fixtureはテスト前に必要な状態やデータを用意するために使う。テスト関数の引数名にfixture名を書けば受け取れる。
import pytest
@pytest.fixture
def user_data():
return {
"email": "test@example.com",
"password": "password",
}
def test_user_email(user_data):
assert user_data["email"] == "test@example.com"
yieldで後始末
DB接続や一時ファイルなど、テスト後に片付けたいものはyieldを使うと分かりやすい。yieldより前がセットアップ、後ろがteardownになる。
@pytest.fixture
def db_session():
session = create_test_session()
try:
yield session
finally:
session.rollback()
session.close()
fixture scope
scopeはfixtureをどの範囲で使い回すかの指定。
| scope | 使い回す範囲 | 自分の使い分け |
|---|---|---|
function |
各テストごと | 基本。DBトランザクションやログイン状態など |
class |
テストクラス単位 | 同じクラスだけで共有するとき |
module |
ファイル単位 | そのテストファイル内で共有したい重い準備 |
package |
パッケージ単位 | 複数モジュールで共有したい場合 |
session |
テスト実行全体で1回 | テスト用アプリ生成など本当に共有してよいもの |
以前は「DBへ登録するfixtureはsessionにした方がよい」と考えていたが、これは使い方による。テストデータまでsessionで共有すると、テスト同士が状態に依存して失敗しやすい。今は各テストを独立させることを優先して、DBデータはfunction scope+ロールバック、またはテストごとに一意なデータを作る方を基本にする。
また、広いscopeのfixtureから狭いscopeのfixtureを直接利用するとScopeMismatchになるので注意。
parametrizeで入力パターンを増やす
同じロジックを複数の値で確認するときは@pytest.mark.parametrizeが便利。
import pytest
@pytest.mark.parametrize(
"a,b,expected",
[
(1, 2, 3),
(0, 5, 5),
(-1, 1, 0),
],
)
def test_add(a, b, expected):
assert a + b == expected
入力値と期待値を並べておけるので、APIのバリデーションテストでも使いやすい。
例外を確認する
エラーになること自体が正しい処理ならpytest.raisesを使う。
import pytest
def divide(a, b):
if b == 0:
raise ValueError("b must not be zero")
return a / b
def test_divide_by_zero():
with pytest.raises(ValueError, match="must not be zero"):
divide(10, 0)
例外型だけでなくmatchでメッセージまで確認すると、意図したエラーか分かりやすい。
Flask APIでよく使う形
Flaskならテスト用appとclientをfixtureにしておくと使いやすい。
# conftest.py
import pytest
from app import create_app
@pytest.fixture(scope="session")
def app():
app = create_app({"TESTING": True})
return app
@pytest.fixture
def client(app):
return app.test_client()
def test_health(client):
response = client.get("/health")
assert response.status_code == 200
assert response.get_json()["status"] == "ok"
POSTやPUTでは、ステータスコードだけでなくJSONの値も合わせて確認する。
def test_create_user(client):
response = client.post(
"/users",
json={"name": "Taro"},
)
assert response.status_code == 201
data = response.get_json()
assert data["name"] == "Taro"
浮動小数点はapprox
小数計算で完全一致を使いたくない場合はpytest.approxを使える。
def test_float():
assert 0.1 + 0.2 == pytest.approx(0.3)
coverageを確認する
pytest-covを入れておけば、テストを実行しながらcoverageを確認できる。
# パッケージ全体
pytest --cov=app tests/
# 未実行行も表示
pytest --cov=app --cov-report=term-missing tests/
# HTMLレポート
pytest --cov=app --cov-report=html tests/
term-missingは未カバーの行番号が出るので、普段はこれが一番分かりやすい。coverageを100%にすること自体を目的にするより、重要な分岐や異常系が抜けていないかを見るために使う。
よく使うオプション
| オプション | 用途 |
|---|---|
-v |
テスト名を詳しく表示 |
-q |
出力を簡潔にする |
-s |
標準出力をキャプチャしない |
-k |
名前でテストを絞り込む |
-x |
最初の失敗で停止 |
--maxfail=N |
N件失敗したら停止 |
--lf |
前回失敗したテストを再実行 |
--tb=short |
トレースバックを短く表示 |
失敗したときに見るところ
pytestの失敗表示は、基本的に一番下のassert差分とテスト名を見る。例えばAPIで期待値が200なのに実際は201なら、実装が間違っているのか、テスト側の期待値が古いのかを確認する。
E assert 201 == 200
FAILED tests/test_users.py::test_create_user
APIの作成成功なら201が正しいことも多いので、「テストが落ちた=実装が悪い」と決めつけず仕様と照らして確認する。
自分用の基本形
# 普段
pytest -q
# 失敗原因を詳しく見る
pytest -v -s tests/test_users.py::test_create_user
# 前回失敗だけ
pytest --lf
# coverage込み
pytest --cov=app --cov-report=term-missing tests/
テストコード自体が複雑になると修正コストも上がるので、fixtureは共有しすぎず、1つのテストでは確認したいことをなるべく絞る。
公式情報メモ
最終更新:2026年9月

