jpskill.com
🛠️ 開発・MCP コミュニティ

pytest

Pythonのテストコード作成、フィクスチャ設定、モック、カバレッジ計測など、pytestを用いたあらゆるテスト作業を支援するSkill。

📜 元の英語説明(参考)

Python testing mastery with pytest, fixtures, parametrize, mocking, and coverage. Use when user asks to "write tests", "add pytest fixtures", "mock a function", "parametrize tests", "run coverage", "debug failing test", "set up conftest", or any Python testing tasks.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Pythonのテストコード作成、フィクスチャ設定、モック、カバレッジ計測など、pytestを用いたあらゆるテスト作業を支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o pytest.zip https://jpskill.com/download/6119.zip && unzip -o pytest.zip && rm pytest.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/6119.zip -OutFile "$d\pytest.zip"; Expand-Archive "$d\pytest.zip" -DestinationPath $d -Force; ri "$d\pytest.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して pytest.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → pytest フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-17
取得日時
2026-05-17
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

pytest

pytest を使用した完全な Python テストツールキットです。

テストの実行

# すべてのテストを実行
pytest

# 特定のファイル/ディレクトリを実行
pytest tests/test_api.py
pytest tests/

# 特定のテストを実行
pytest tests/test_api.py::test_login
pytest tests/test_api.py::TestUserClass::test_create

# 詳細な出力
pytest -v
pytest -vv  # さらに詳細

# 最初の失敗で停止
pytest -x

# 最後に失敗したテストを実行
pytest --lf

# 失敗したテストを最初に実行し、次に残りを実行
pytest --ff

# print 出力を表示
pytest -s

# 並列実行 (pytest-xdist が必要)
pytest -n auto
pytest -n 4

フィクスチャ

import pytest

# 基本的なフィクスチャ
@pytest.fixture
def user():
    return {"name": "Alice", "email": "alice@test.com"}

# teardown 付きフィクスチャ
@pytest.fixture
def db_connection():
    conn = create_connection()
    yield conn
    conn.close()

# 自動実行フィクスチャ (すべてのテストで実行)
@pytest.fixture(autouse=True)
def reset_state():
    State.reset()
    yield
    State.cleanup()

# スコープ付きフィクスチャ
@pytest.fixture(scope="module")
def expensive_resource():
    return load_heavy_thing()

# scope オプション: "function" (デフォルト), "class", "module", "package", "session"

# パラメータ付きフィクスチャ
@pytest.fixture(params=["sqlite", "postgres", "mysql"])
def db_engine(request):
    return create_engine(request.param)

# フィクスチャの使用
def test_user_name(user):
    assert user["name"] == "Alice"

パラメータ化

# 基本的なパラメータ化
@pytest.mark.parametrize("input,expected", [
    ("hello", 5),
    ("", 0),
    ("world", 5),
])
def test_string_length(input, expected):
    assert len(input) == expected

# 複数のパラメータ
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_combinations(x, y):
    pass  # 4回実行されます: (0,2), (0,3), (1,2), (1,3)

# ID 付き
@pytest.mark.parametrize("input,expected", [
    pytest.param("admin", True, id="admin-user"),
    pytest.param("guest", False, id="guest-user"),
])
def test_is_admin(input, expected):
    assert is_admin(input) == expected

モック

from unittest.mock import Mock, patch, MagicMock

# patch デコレータ
@patch("myapp.services.send_email")
def test_registration(mock_send):
    register_user("alice@test.com")
    mock_send.assert_called_once_with("alice@test.com", subject="Welcome")

# コンテキストマネージャとしての patch
def test_api_call():
    with patch("myapp.client.requests.get") as mock_get:
        mock_get.return_value.json.return_value = {"status": "ok"}
        result = fetch_status()
        assert result == "ok"

# Mock フィクスチャ (pytest-mock)
def test_with_mocker(mocker):
    mock_db = mocker.patch("myapp.db.query")
    mock_db.return_value = [{"id": 1}]
    result = get_users()
    assert len(result) == 1

# 副作用 (Side effects)
mock_func = Mock(side_effect=ValueError("boom"))
mock_func = Mock(side_effect=[1, 2, 3])  # 順次返します
mock_func = Mock(side_effect=lambda x: x * 2)

# Spec モック (属性エラーを捕捉)
mock_obj = Mock(spec=MyClass)

マーカー

# スキップ
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
    pass

# 条件付きスキップ
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_permissions():
    pass

# 期待される失敗
@pytest.mark.xfail(reason="Known bug #123")
def test_known_bug():
    pass

# カスタムマーカー
@pytest.mark.slow
def test_heavy_computation():
    pass

# マーカーで実行: pytest -m slow
# 除外して実行: pytest -m "not slow"

# pytest.ini または pyproject.toml でマーカーを登録
# [tool.pytest.ini_options]
# markers = ["slow: marks tests as slow"]

アサーション

# 基本
assert result == expected
assert item in collection
assert value is None

# 例外テスト
with pytest.raises(ValueError):
    int("not_a_number")

with pytest.raises(ValueError, match="invalid literal"):
    int("not_a_number")

# 近似値
assert 0.1 + 0.2 == pytest.approx(0.3)
assert result == pytest.approx(expected, rel=1e-3)

# 警告
with pytest.warns(DeprecationWarning):
    deprecated_function()

カバレッジ

# インストール
pip install pytest-cov

# カバレッジ付きで実行
pytest --cov=myapp
pytest --cov=myapp --cov-report=html
pytest --cov=myapp --cov-report=term-missing
pytest --cov=myapp --cov-branch  # ブランチカバレッジ

# 最小しきい値
pytest --cov=myapp --cov-fail-under=80

conftest.py

# tests/conftest.py - すべてのテストで利用可能な共有フィクスチャ

import pytest

@pytest.fixture
def app():
    """テストアプリケーションを作成します。"""
    app = create_app(testing=True)
    yield app

@pytest.fixture
def client(app):
    """テストクライアントを作成します。"""
    return app.test_client()

@pytest.fixture
def auth_headers():
    """認証ヘッダーを作成します。"""
    token = create_test_token()
    return {"Authorization": f"Bearer {token}"}

pyproject.toml 設定

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
addopts = "-v --tb=short --strict-markers"
markers = [
    "slow: marks tests as slow",
    "integration: integration tests",
]
filterwarnings = [
    "ignore::DeprecationWarning",
]

参照

高度なパターン、プラグイン、非同期テストについては、references/patterns.md を参照してください。

📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

pytest

Complete Python testing toolkit with pytest.

Running Tests

# Run all tests
pytest

# Run specific file/directory
pytest tests/test_api.py
pytest tests/

# Run specific test
pytest tests/test_api.py::test_login
pytest tests/test_api.py::TestUserClass::test_create

# Verbose output
pytest -v
pytest -vv  # Extra verbose

# Stop on first failure
pytest -x

# Run last failed
pytest --lf

# Run failed first, then rest
pytest --ff

# Show print output
pytest -s

# Parallel (requires pytest-xdist)
pytest -n auto
pytest -n 4

Fixtures

import pytest

# Basic fixture
@pytest.fixture
def user():
    return {"name": "Alice", "email": "alice@test.com"}

# Fixture with teardown
@pytest.fixture
def db_connection():
    conn = create_connection()
    yield conn
    conn.close()

# Autouse fixture (runs for every test)
@pytest.fixture(autouse=True)
def reset_state():
    State.reset()
    yield
    State.cleanup()

# Scoped fixtures
@pytest.fixture(scope="module")
def expensive_resource():
    return load_heavy_thing()

# scope options: "function" (default), "class", "module", "package", "session"

# Fixture with params
@pytest.fixture(params=["sqlite", "postgres", "mysql"])
def db_engine(request):
    return create_engine(request.param)

# Using fixtures
def test_user_name(user):
    assert user["name"] == "Alice"

Parametrize

# Basic parametrize
@pytest.mark.parametrize("input,expected", [
    ("hello", 5),
    ("", 0),
    ("world", 5),
])
def test_string_length(input, expected):
    assert len(input) == expected

# Multiple parameters
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_combinations(x, y):
    pass  # Runs 4 times: (0,2), (0,3), (1,2), (1,3)

# With IDs
@pytest.mark.parametrize("input,expected", [
    pytest.param("admin", True, id="admin-user"),
    pytest.param("guest", False, id="guest-user"),
])
def test_is_admin(input, expected):
    assert is_admin(input) == expected

Mocking

from unittest.mock import Mock, patch, MagicMock

# patch decorator
@patch("myapp.services.send_email")
def test_registration(mock_send):
    register_user("alice@test.com")
    mock_send.assert_called_once_with("alice@test.com", subject="Welcome")

# patch as context manager
def test_api_call():
    with patch("myapp.client.requests.get") as mock_get:
        mock_get.return_value.json.return_value = {"status": "ok"}
        result = fetch_status()
        assert result == "ok"

# Mock fixture (pytest-mock)
def test_with_mocker(mocker):
    mock_db = mocker.patch("myapp.db.query")
    mock_db.return_value = [{"id": 1}]
    result = get_users()
    assert len(result) == 1

# Side effects
mock_func = Mock(side_effect=ValueError("boom"))
mock_func = Mock(side_effect=[1, 2, 3])  # Returns sequentially
mock_func = Mock(side_effect=lambda x: x * 2)

# Spec mocking (catches attribute errors)
mock_obj = Mock(spec=MyClass)

Markers

# Skip
@pytest.mark.skip(reason="Not implemented yet")
def test_future_feature():
    pass

# Skip conditionally
@pytest.mark.skipif(sys.platform == "win32", reason="Unix only")
def test_unix_permissions():
    pass

# Expected failure
@pytest.mark.xfail(reason="Known bug #123")
def test_known_bug():
    pass

# Custom markers
@pytest.mark.slow
def test_heavy_computation():
    pass

# Run by marker: pytest -m slow
# Run excluding: pytest -m "not slow"

# Register markers in pytest.ini or pyproject.toml
# [tool.pytest.ini_options]
# markers = ["slow: marks tests as slow"]

Assertions

# Basic
assert result == expected
assert item in collection
assert value is None

# Exception testing
with pytest.raises(ValueError):
    int("not_a_number")

with pytest.raises(ValueError, match="invalid literal"):
    int("not_a_number")

# Approximate
assert 0.1 + 0.2 == pytest.approx(0.3)
assert result == pytest.approx(expected, rel=1e-3)

# Warnings
with pytest.warns(DeprecationWarning):
    deprecated_function()

Coverage

# Install
pip install pytest-cov

# Run with coverage
pytest --cov=myapp
pytest --cov=myapp --cov-report=html
pytest --cov=myapp --cov-report=term-missing
pytest --cov=myapp --cov-branch  # Branch coverage

# Minimum threshold
pytest --cov=myapp --cov-fail-under=80

conftest.py

# tests/conftest.py - Shared fixtures available to all tests

import pytest

@pytest.fixture
def app():
    """Create test application."""
    app = create_app(testing=True)
    yield app

@pytest.fixture
def client(app):
    """Create test client."""
    return app.test_client()

@pytest.fixture
def auth_headers():
    """Create auth headers."""
    token = create_test_token()
    return {"Authorization": f"Bearer {token}"}

pyproject.toml Config

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_functions = ["test_*"]
addopts = "-v --tb=short --strict-markers"
markers = [
    "slow: marks tests as slow",
    "integration: integration tests",
]
filterwarnings = [
    "ignore::DeprecationWarning",
]

Reference

For advanced patterns, plugins, and async testing: references/patterns.md