pytest について
Python開発者向けのpytest実用リファレンスです。テスト構成、フィクスチャ、モック、パラメーター化、マーカー、非同期テストに加え、よく使うコマンドとProwler SDK固有のテスト資料を案内します。
主な機能
- 01テストクラスとアサーション
- 02フィクスチャとconftest.py
- 03unittest.mockによるモック
- 04パラメーター化テスト
- 05マーカーと非同期テスト
- 06よく使うpytestコマンド
活用シーン
- 01Pythonのユニットテスト作成
- 02フィクスチャによるセットアップの共有
- 03外部サービスを呼び出すコードのテスト
- 04テストの絞り込みやカバレッジ測定
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ prowler-cloud/ prowler --skill pytestインストール後、Claude Code で/pytestを入力して読み込まれたか確認します。
同梱ファイルreferences/prowler-testing.md
詳細
基本的なテスト構造
import pytest
class TestUserService:
def test_create_user_success(self):
user = create_user(name="John", email="[email protected]")
assert user.name == "John"
assert user.email == "[email protected]"
def test_create_user_invalid_email_fails(self):
with pytest.raises(ValueError, match="Invalid email"):
create_user(name="John", email="invalid")
フィクスチャ
import pytest
@pytest.fixture
def user():
"""Create a test user."""
return User(name="Test User", email="[email protected]")
@pytest.fixture
def authenticated_client(client, user):
"""Client with authenticated user."""
client.force_login(user)
return client
# Fixture with teardown
@pytest.fixture
def temp_file():
path = Path("/tmp/test_file.txt")
path.write_text("test content")
yield path # Test runs here
path.unlink() # Cleanup after test
# Fixture scopes
@pytest.fixture(scope="module") # Once per module
@pytest.fixture(scope="class") # Once per class
@pytest.fixture(scope="session") # Once per test session
conftest.py
# tests/conftest.py - Shared fixtures
import pytest
@pytest.fixture
def db_session():
session = create_session()
yield session
session.rollback()
@pytest.fixture
def api_client():
return TestClient(app)
モック
from unittest.mock import patch, MagicMock
class TestPaymentService:
def test_process_payment_success(self):
with patch("services.payment.stripe_client") as mock_stripe:
mock_stripe.charge.return_value = {"id": "ch_123", "status": "succeeded"}
result = process_payment(amount=100)
assert result["status"] == "succeeded"
mock_stripe.charge.assert_called_once_with(amount=100)
def test_process_payment_failure(self):
with patch("services.payment.stripe_client") as mock_stripe:
mock_stripe.charge.side_effect = PaymentError("Card declined")
with pytest.raises(PaymentError):
process_payment(amount=100)
# MagicMock for complex objects
def test_with_mock_object():
mock_user = MagicMock()
mock_user.id = "user-123"
mock_user.name = "Test User"
mock_user.is_active = True
result = get_user_info(mock_user)
assert result["name"] == "Test User"
パラメーター化
@pytest.mark.parametrize("input,expected", [
("hello", "HELLO"),
("world", "WORLD"),
("pytest", "PYTEST"),
])
def test_uppercase(input, expected):
assert input.upper() == expected
@pytest.mark.parametrize("email,is_valid", [
("[email protected]", True),
("invalid-email", False),
("", False),
("[email protected]", False),
])
def test_email_validation(email, is_valid):
assert validate_email(email) == is_valid
マーカー
# pytest.ini or pyproject.toml
[tool.pytest.ini_options]
markers = [
"slow: marks tests as slow",
"integration: marks integration tests",
]
# Usage
@pytest.mark.slow
def test_large_data_processing():
...
@pytest.mark.integration
def test_database_connection():
...
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
...
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_specific():
...
# Run specific markers
# pytest -m "not slow"
# pytest -m "integration"
非同期テスト
import pytest
@pytest.mark.asyncio
async def test_async_function():
result = await async_fetch_data()
assert result is not None
コマンド
pytest # Run all tests
pytest -v # Verbose output
pytest -x # Stop on first failure
pytest -k "test_user" # Filter by name
pytest -m "not slow" # Filter by marker
pytest --cov=src # With coverage
pytest -n auto # Parallel (pytest-xdist)
pytest --tb=short # Short traceback
参考資料
pytest の一般的なドキュメントについては、次を参照してください。
- 公式ドキュメント:https://docs.pytest.org/en/stable/
プロバイダー固有のパターン(moto、MagicMock)を使用した Prowler SDK のテストについては、次を参照してください。
コメント
Markdown 対応