pytestでクラスを使う
pytestではテストをクラスにまとめることができます。
テストをクラスにまとめてグループ化することで、テストの構造が明確になります。
また、共通のsetupをクラスレベルで管理できるようになり、
@pytest.fixture
を使ってセットアップを一度だけ記述することでコードの重複を避けることができます。
環境
- python 3.11.0
- pytest 8.0.0
テスト対象コードを用意する
テストを書くための、外部APIをたたくコードを用意しました。
class APIClient: def __init__(self, url: str): self.url = url def get_status(self): try: response = requests.get(self.url) return response.json() except RequestException as e: raise HTTPException(status_code=500, detail=str(e)) def check_capacity(self): status = self.get_status() if status["capacity"] == "Full": return "No capacity" elif status["capacity"] == "Available": return "Capacity available" else: return "Status check failed"
pytestを書いてみる
import pytest from main import APIClient class TestAPIClient: @pytest.fixture(autouse=True) def setup(self, mocker): self.client = APIClient("http://test") self.mock_get_status = mocker.patch.object( self.client, "get_status", autospec=True ) def test_check_capacity_full(self): self.mock_get_status.return_value = {"capacity": "Full"} assert self.client.check_capacity() == "No capacity" def test_check_capacity_available(self): self.mock_get_status.return_value = {"capacity": "Available"} assert self.client.check_capacity() == "Capacity available" def test_check_capacity_failed(self): self.mock_get_status.return_value = {"capacity": "Unknown"} assert self.client.check_capacity() == "Status check failed"
@pytest.fixture(autouse=True)
@pytest.fixtureデコレータを使用してテストの前準備を行い、autouse=True
にすることで、すべてのテストで自動的にsetupが実行されるようにしました How to use fixtures — pytest documentationself.client = APIClient("http://test")
テスト対象となるAPIClientクラスのインスタンスを作成し、テスト用のURLを渡して初期化self.mock_get_status = mocker.patch.object(...):
mocker.patch.objectメソッドで、実際のHTTPリクエストを行わずにget_statusメソッドの振る舞いを模倣できます。
autospec=True
を加えることで間違ったシグネチャで呼び出された場合は TypeError を発生させるようにしました。 unittest.mock --- モックオブジェクトライブラリ — Python 3.11.7 ドキュメント
注意点
継承を使って凝ったことをしようとすると、メンテナンスが複雑になるので、グループ化を目的とすることにとどめておくことが推奨されています。