pytest-advanced について
堅牢で保守しやすいテストスイートを作る Python 開発者向けの pytest 応用ガイドです。フィクスチャ階層、複雑なパラメーター化、プラグイン、非同期テスト、並列実行、CI 連携を扱います。
主な機能
- 01スコープ別・ファクトリー型フィクスチャの構成
- 02複雑なパラメーター化とマーカー
- 03pytest プラグインの設定
- 04非同期テストとモック
- 05並列実行と CI 連携
活用シーン
- 01複数パッケージのテストでフィクスチャを共有
- 02複数の入力やデータベースバックエンドをテスト
- 03並列実行で失敗箇所を特定
- 04CI でカバレッジとテスト結果を出力
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ laurigates/ claude-plugins --skill pytest-advancedインストール後、Claude Code で/pytest-advancedを入力して読み込まれたか確認します。
同梱ファイルREFERENCE.md
詳細
高度な Pytest パターン
堅牢で保守しやすいテストスイートを実現するための、pytest の高度な機能です。
このスキルを使う場合
| 次の場合はこのスキルを使います… | 次の場合は python-testing を使います… |
|---|---|
| スコープやファクトリーを使ったフィクスチャを書く | 基本的なテスト構成について質問する |
| 複雑なデータでパラメーター化する | シンプルな assert パターンを使う |
| pytest プラグイン(cov、xdist)を設定する | 既存のテストを実行する |
| conftest.py の階層を整理する | テスト検出の基本を確認する |
| pytest-asyncio で非同期テストを行う | 同期ユニットテストを行う |
インストール
# Core + common plugins
uv add --dev pytest pytest-cov pytest-asyncio pytest-xdist pytest-mock
設定(pyproject.toml)
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"-v",
"--strict-markers",
"--tb=short",
"-ra",
"--cov=src",
"--cov-report=term-missing",
"--cov-fail-under=80",
]
markers = [
"slow: marks tests as slow (deselect with '-m \"not slow\"')",
"integration: marks tests as integration tests",
]
asyncio_mode = "auto"
[tool.coverage.run]
branch = true
source = ["src"]
[tool.coverage.report]
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:", "@abstractmethod"]
フィクスチャ
スコープとライフサイクル
import pytest
from typing import Generator
# function (default) - fresh per test
@pytest.fixture
def db() -> Generator[Database, None, None]:
database = Database(":memory:")
database.create_tables()
yield database
database.close()
# session - shared across all tests
@pytest.fixture(scope="session")
def app():
return create_app("testing")
# autouse - applies automatically
@pytest.fixture(autouse=True)
def reset_state():
clear_cache()
yield
| スコープ | 有効期間 |
|---|---|
function | 各テスト(デフォルト) |
class | 各テストクラス |
module | 各テストファイル |
session | テスト実行全体 |
パラメーター化されたフィクスチャ
@pytest.fixture(params=["sqlite", "postgres", "mysql"])
def database_backend(request) -> str:
return request.param # Test runs 3 times
# Indirect parametrization
@pytest.fixture
def user(request) -> User:
return User(**request.param)
@pytest.mark.parametrize("user", [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
], indirect=True)
def test_user_validation(user: User):
assert user.name
ファクトリーパターン
@pytest.fixture
def user_factory() -> Callable[[str], User]:
created: list[User] = []
def _create(name: str, **kwargs) -> User:
user = User(name=name, **kwargs)
created.append(user)
return user
yield _create
for u in created:
u.delete()
マーカー
# Built-in markers
@pytest.mark.skip(reason="Not implemented")
@pytest.mark.skipif(sys.version_info < (3, 12), reason="Requires 3.12+")
@pytest.mark.xfail(reason="Known bug #123")
@pytest.mark.timeout(10)
# Parametrize
@pytest.mark.parametrize("input,expected", [
pytest.param(2, 4, id="two"),
pytest.param(3, 9, id="three"),
pytest.param(-2, 4, id="negative"),
])
def test_square(input: int, expected: int):
assert input ** 2 == expected
# Run by marker
pytest -m unit # Only unit tests
pytest -m "not slow" # Skip slow tests
pytest -m "integration and not slow" # Combine markers
主なプラグイン
| プラグイン | 目的 | 主なコマンド |
|---|---|---|
| pytest-cov | カバレッジ | pytest --cov=src --cov-report=term-missing |
| pytest-xdist | 並列実行 | pytest -n auto |
| pytest-asyncio | 非同期テスト | 設定で asyncio_mode = "auto" |
| pytest-mock | モック | mocker フィクスチャ |
| pytest-timeout | タイムアウト | @pytest.mark.timeout(10) |
非同期テスト(pytest-asyncio)
@pytest.mark.asyncio
async def test_async_function():
result = await fetch_data()
assert result is not None
@pytest.fixture
async def async_client() -> AsyncGenerator[AsyncClient, None]:
async with AsyncClient() as client:
yield client
モック(pytest-mock)
def test_with_mock(mocker):
mock_api = mocker.patch("myapp.external.api_call")
mock_api.return_value = {"data": "test"}
result = my_function()
assert result["data"] == "test"
mock_api.assert_called_once()
テストの実行
# Execution
pytest # All tests
pytest tests/test_models.py::test_user # Specific test
pytest -k "user and not slow" # Pattern matching
# Parallel
pytest -n auto # All CPUs
pytest -n 4 # 4 workers
# Coverage
pytest --cov=src --cov-report=html --cov-report=term-missing
# Failed tests
pytest --lf # Last failed only
pytest --ff # Failed first
pytest -x # Stop on first failure
pytest --maxfail=3 # Stop after 3
# Debugging
pytest -x --pdb # Debug on failure
pytest -s # Show print output
pytest --collect-only # Dry run
CI との統合
# .github/workflows/test.yml
- name: Run tests
run: |
uv run pytest \
--cov=src \
--cov-report=xml \
--cov-report=term-missing \
--junitxml=test-results.xml
エージェント向けの最適化
| コンテキスト | コマンド |
|---|---|
| クイックチェック | pytest -x --tb=short -q |
| 即時失敗 | pytest -x --maxfail=1 --tb=short |
| 並列で高速実行 | pytest -n auto -x --tb=short -q |
| 特定のテスト | pytest tests/test_foo.py::test_bar -v |
| マーカーで指定 | pytest -m "not slow" -x --tb=short |
| カバレッジチェック | pytest --cov=src --cov-fail-under=80 -q |
| CI モード | pytest --junitxml=results.xml --cov-report=xml -q |
| 直近の失敗 | pytest --lf --tb=short |
| デバッグ | pytest -x --pdb -s |
conftest.py の階層、非同期テスト、テストの整理、一般的なパターンについて詳しくは、REFERENCE.md を参照してください。
コメント
Markdown 対応