Pytest Testing について
Python 開発者向けに、pytest を使ったテスト設計から CI 連携までを学ぶスキルです。
主な機能
- 01ユニット・統合・機能テスト
- 02フィクスチャとテスト準備
- 03外部依存のモック
- 04テスト駆動開発
- 05カバレッジと CI 連携
活用シーン
- 01Python プロジェクトの pytest テスト作成
- 02モックリクエストによる API テスト
- 03カバレッジレポートと CI チェックの追加
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pluginagentmarketplace/ custom-plugin-python --skill pytest-testingインストール後、Claude Code で/pytest-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/config.yamlreferences/GUIDE.mdscripts/helper.py詳細
Pytest によるテスト
概要
Python で最も人気のあるテストフレームワーク、pytest を使ってソフトウェアテストを習得しましょう。テスト駆動開発(TDD)を学び、保守しやすいテストを書き、包括的なテスト戦略によってコード品質を確保します。
学習目標
- pytest でユニットテスト、統合テスト、機能テストを書く
- テストのセットアップと後処理にフィクスチャを使う
- 外部依存関係を効果的にモックする
- テスト駆動開発(TDD)を実践する
- コードカバレッジを測定し、改善する
- テストを CI/CD パイプラインに統合する
主なトピック
1. Pytest の基礎
- テストの検出と命名規則
- アサーションと比較
- テストの構成(ファイル、クラス、モジュール)
- テストの実行(コマンドラインオプション)
- マーカーとテストの選択
- パラメーター化テスト
コード例:
# test_calculator.py
import pytest
def add(a, b):
return a + b
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
# Basic test
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0, 0) == 0
# Test exceptions
def test_divide_by_zero():
with pytest.raises(ValueError, match="Cannot divide by zero"):
divide(10, 0)
# Parametrized test
@pytest.mark.parametrize("a,b,expected", [
(10, 2, 5),
(20, 4, 5),
(100, 10, 10),
(-10, 2, -5),
])
def test_divide(a, b, expected):
assert divide(a, b) == expected
# Test with marker
@pytest.mark.slow
def test_complex_operation():
# This test takes a long time
result = sum(range(1000000))
assert result == 499999500000
2. フィクスチャとテストのセットアップ
- フィクスチャのスコープ(関数、クラス、モジュール、セッション)
- フィクスチャの依存関係
- パラメーター化フィクスチャ
- 組み込みフィクスチャ(tmpdir、capsys、monkeypatch)
- 共有フィクスチャ用の conftest.py
コード例:
# conftest.py
import pytest
import tempfile
from pathlib import Path
@pytest.fixture
def sample_data():
"""Provide sample data for tests"""
return {
'users': [
{'id': 1, 'name': 'Alice', 'email': '[email protected]'},
{'id': 2, 'name': 'Bob', 'email': '[email protected]'},
]
}
@pytest.fixture
def temp_file():
"""Create temporary file for testing"""
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
f.write("Test data")
temp_path = f.name
yield temp_path
# Cleanup
Path(temp_path).unlink()
@pytest.fixture(scope='module')
def database_connection():
"""Module-scoped database connection"""
db = DatabaseConnection('test.db')
db.connect()
yield db
db.close()
# test_users.py
def test_user_count(sample_data):
assert len(sample_data['users']) == 2
def test_user_names(sample_data):
names = [user['name'] for user in sample_data['users']]
assert 'Alice' in names
assert 'Bob' in names
def test_file_operations(temp_file):
content = Path(temp_file).read_text()
assert content == "Test data"
3. モックとテストダブル
- unittest.mock の基礎
- 関数とメソッドのモック
- オブジェクトへのパッチ適用
- モックのアサーション
- 副作用と戻り値
- 外部依存関係を使ったテスト
コード例:
# api_client.py
import requests
class APIClient:
def __init__(self, base_url):
self.base_url = base_url
def get_user(self, user_id):
response = requests.get(f"{self.base_url}/users/{user_id}")
response.raise_for_status()
return response.json()
def create_user(self, user_data):
response = requests.post(f"{self.base_url}/users", json=user_data)
response.raise_for_status()
return response.json()
# test_api_client.py
from unittest.mock import Mock, patch
import pytest
@patch('api_client.requests.get')
def test_get_user(mock_get):
# Setup mock
mock_response = Mock()
mock_response.json.return_value = {'id': 1, 'name': 'Alice'}
mock_response.raise_for_status.return_value = None
mock_get.return_value = mock_response
# Test
client = APIClient('https://api.example.com')
user = client.get_user(1)
# Assertions
assert user['name'] == 'Alice'
mock_get.assert_called_once_with('https://api.example.com/users/1')
@patch('api_client.requests.post')
def test_create_user(mock_post):
# Setup mock
mock_response = Mock()
mock_response.json.return_value = {'id': 3, 'name': 'Charlie'}
mock_post.return_value = mock_response
# Test
client = APIClient('https://api.example.com')
user_data = {'name': 'Charlie', 'email': '[email protected]'}
result = client.create_user(user_data)
# Assertions
assert result['id'] == 3
mock_post.assert_called_once_with(
'https://api.example.com/users',
json=user_data
)
4. カバレッジと CI/CD の統合
- pytest-cov でコードカバレッジを測定する
- カバレッジレポート(ターミナル、HTML、XML)
- カバレッジのしきい値を設定する
- GitHub Actions との統合
- GitLab CI との統合
- コミット前フック
コード例:
# pytest.ini
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
--cov=myapp
--cov-report=html
--cov-report=term-missing
--cov-fail-under=80
-v
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-cov
- name: Run tests
run: |
pytest --cov=myapp --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
# Command line usage
# Run all tests
pytest
# Run with coverage
pytest --cov=myapp
# Generate HTML coverage report
pytest --cov=myapp --cov-report=html
# Run specific test file
pytest tests/test_api.py
# Run tests with marker
pytest -m slow
# Run tests with verbose output
pytest -v
# Stop on first failure
pytest -x
実践演習
プロジェクト 1:TDD で作る電卓
テスト駆動開発を使って電卓を作成します。
要件:
- 実装の前にテストを書く
- 基本的な演算(加算、減算、乗算、除算)
- エラー処理(ゼロ除算)
- 科学計算(累乗、平方根、対数)
- テストカバレッジ 90% 超
主なスキル: TDD のワークフロー、パラメーター化テスト、例外テスト
プロジェクト 2:API テストスイート
REST API の包括的なテストスイートを作成します。
要件:
- HTTP リクエストをモックする
- CRUD 操作をテストする
- エラー処理をテストする
- 認証をテストする
- 統合テスト
- CI/CD パイプラインのセットアップ
主なスキル: モック、フィクスチャ、統合テスト
プロジェクト 3:データベースのテスト
フィクスチャとトランザクションを使ってデータベース操作をテストします。
要件:
- テスト用データベースのフィクスチャをセットアップする
- CRUD 操作をテストする
- トランザクションをロールバックする
- データ検証
- パフォーマンステスト
- カバレッジレポート
主なスキル: データベースフィクスチャ、クリーンアップ、パフォーマンステスト
評価基準
- 明確で保守しやすいテストを書く
- フィクスチャを適切に使う
- 外部依存関係を効果的にモックする
- コードカバレッジ 80% 超を達成する
- TDD の原則に従う
- テストを CI/CD に統合する
- 意味のあるアサーションを書く
リソース
公式ドキュメント
- Pytest ドキュメント - 公式ドキュメント
- pytest-cov - カバレッジプラグイン
- unittest.mock - モックライブラリ
学習プラットフォーム
- Python によるテスト駆動開発 - TDD の書籍
- pytest による Python テスト - Brian Okken の書籍
- Real Python のテスト - チュートリアル
ツール
- pytest-xdist - 並列テスト
- pytest-mock - モック用ヘルパー
- Hypothesis - プロパティベーステスト
- tox - テスト自動化
次のステップ
pytest を習得したら、次のトピックに取り組みましょう。
- プロパティベーステスト - Hypothesis ライブラリ
- パフォーマンステスト - pytest-benchmark
- ミューテーションテスト - mutmut
- 負荷テスト - Locust、pytest-load
コメント
Markdown 対応