Source profileQuality 74/100

affaan-m/ECC/docs/ja-JP/skills/python-testing/SKILL.md

python-testing

Use it for testing and engineering tasks; the detail page covers purpose, installation, and practical steps.

Source repository stars
234,327
Declared platforms
0
Static risk flags
3
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

pytest、TDD方法論、ベストプラクティスを使用したPythonアプリケーションの包括的なテスト戦略。

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/ja-JP/skills/python-testing"
    Safe inspection promptEditorial

    Inspect the Agent Skill "python-testing" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/ja-JP/skills/python-testing/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Step 1: Write failing test (RED)

      def testaddnumbers(): result = add(2, 3) assert result == 5

      def testaddnumbers(): result = add(2, 3) assert result == 5
    2. 02

      Step 2: Write minimal implementation (GREEN)

      def add(a, b): return a + b

      def add(a, b): return a + b
    3. 03

      Step 3: Refactor if needed (REFACTOR)

      bash pytest --cov=mypackage --cov-report=term-missing --cov-report=html python import pytest

      bash pytest --cov=mypackage --cov-report=term-missing --cov-report=html python import pytestdef testaddition(): """Test basic addition.""" assert 2 + 2 == 4def teststringuppercase(): """Test string uppercasing.""" text = "hello" assert text.upper() == "HELLO"
    4. 04

      いつ有効化するか

      新しいPythonコードを書くとき(TDDに従う:赤、緑、リファクタリング)

      新しいPythonコードを書くとき(TDDに従う:赤、緑、リファクタリング)Pythonプロジェクトのテストスイートを設計するときPythonテストカバレッジをレビューするとき
    5. 05

      核となるテスト哲学

      1. 赤: 期待される動作のための失敗するテストを書く 2. 緑: テストを通過させるための最小限のコードを書く 3. リファクタリング: テストを通過させたままコードを改善する

      赤: 期待される動作のための失敗するテストを書く緑: テストを通過させるための最小限のコードを書くリファクタリング: テストを通過させたままコードを改善する

    Permission review

    Static risk signals and limitations

    Network access

    medium · line 318

    The documentation includes network, browsing, or remote request actions.

    response = requests.get("https://api.example.com")

    Reads files

    low · line 406

    The documentation asks the agent to read local files, directories, or repositories.

    mock_file.return_value.read.return_value = "file content"

    Writes files

    medium · line 558

    The documentation asks the agent to create, modify, or delete local files.

    os.unlink(temp_path)

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score74/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/ja-JP/skills/python-testing/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Pythonテストパターン

    pytest、TDD方法論、ベストプラクティスを使用したPythonアプリケーションの包括的なテスト戦略。

    いつ有効化するか

    • 新しいPythonコードを書くとき(TDDに従う:赤、緑、リファクタリング)
    • Pythonプロジェクトのテストスイートを設計するとき
    • Pythonテストカバレッジをレビューするとき
    • テストインフラストラクチャをセットアップするとき

    核となるテスト哲学

    テスト駆動開発(TDD)

    常にTDDサイクルに従います。

    1. : 期待される動作のための失敗するテストを書く
    2. : テストを通過させるための最小限のコードを書く
    3. リファクタリング: テストを通過させたままコードを改善する
    # Step 1: Write failing test (RED)
    def test_add_numbers():
        result = add(2, 3)
        assert result == 5
    
    # Step 2: Write minimal implementation (GREEN)
    def add(a, b):
        return a + b
    
    # Step 3: Refactor if needed (REFACTOR)
    

    カバレッジ要件

    • 目標: 80%以上のコードカバレッジ
    • クリティカルパス: 100%のカバレッジが必要
    • pytest --covを使用してカバレッジを測定
    pytest --cov=mypackage --cov-report=term-missing --cov-report=html
    

    pytestの基礎

    基本的なテスト構造

    import pytest
    
    def test_addition():
        """Test basic addition."""
        assert 2 + 2 == 4
    
    def test_string_uppercase():
        """Test string uppercasing."""
        text = "hello"
        assert text.upper() == "HELLO"
    
    def test_list_append():
        """Test list append."""
        items = [1, 2, 3]
        items.append(4)
        assert 4 in items
        assert len(items) == 4
    

    アサーション

    # Equality
    assert result == expected
    
    # Inequality
    assert result != unexpected
    
    # Truthiness
    assert result  # Truthy
    assert not result  # Falsy
    assert result is True  # Exactly True
    assert result is False  # Exactly False
    assert result is None  # Exactly None
    
    # Membership
    assert item in collection
    assert item not in collection
    
    # Comparisons
    assert result > 0
    assert 0 <= result <= 100
    
    # Type checking
    assert isinstance(result, str)
    
    # Exception testing (preferred approach)
    with pytest.raises(ValueError):
        raise ValueError("error message")
    
    # Check exception message
    with pytest.raises(ValueError, match="invalid input"):
        raise ValueError("invalid input provided")
    
    # Check exception attributes
    with pytest.raises(ValueError) as exc_info:
        raise ValueError("error message")
    assert str(exc_info.value) == "error message"
    

    フィクスチャ

    基本的なフィクスチャ使用

    import pytest
    
    @pytest.fixture
    def sample_data():
        """Fixture providing sample data."""
        return {"name": "Alice", "age": 30}
    
    def test_sample_data(sample_data):
        """Test using the fixture."""
        assert sample_data["name"] == "Alice"
        assert sample_data["age"] == 30
    

    セットアップ/ティアダウン付きフィクスチャ

    @pytest.fixture
    def database():
        """Fixture with setup and teardown."""
        # Setup
        db = Database(":memory:")
        db.create_tables()
        db.insert_test_data()
    
        yield db  # Provide to test
    
        # Teardown
        db.close()
    
    def test_database_query(database):
        """Test database operations."""
        result = database.query("SELECT * FROM users")
        assert len(result) > 0
    

    フィクスチャスコープ

    # Function scope (default) - runs for each test
    @pytest.fixture
    def temp_file():
        with open("temp.txt", "w") as f:
            yield f
        os.remove("temp.txt")
    
    # Module scope - runs once per module
    @pytest.fixture(scope="module")
    def module_db():
        db = Database(":memory:")
        db.create_tables()
        yield db
        db.close()
    
    # Session scope - runs once per test session
    @pytest.fixture(scope="session")
    def shared_resource():
        resource = ExpensiveResource()
        yield resource
        resource.cleanup()
    

    パラメータ付きフィクスチャ

    @pytest.fixture(params=[1, 2, 3])
    def number(request):
        """Parameterized fixture."""
        return request.param
    
    def test_numbers(number):
        """Test runs 3 times, once for each parameter."""
        assert number > 0
    

    複数のフィクスチャ使用

    @pytest.fixture
    def user():
        return User(id=1, name="Alice")
    
    @pytest.fixture
    def admin():
        return User(id=2, name="Admin", role="admin")
    
    def test_user_admin_interaction(user, admin):
        """Test using multiple fixtures."""
        assert admin.can_manage(user)
    

    自動使用フィクスチャ

    @pytest.fixture(autouse=True)
    def reset_config():
        """Automatically runs before every test."""
        Config.reset()
        yield
        Config.cleanup()
    
    def test_without_fixture_call():
        # reset_config runs automatically
        assert Config.get_setting("debug") is False
    

    共有フィクスチャ用のConftest.py

    # tests/conftest.py
    import pytest
    
    @pytest.fixture
    def client():
        """Shared fixture for all tests."""
        app = create_app(testing=True)
        with app.test_client() as client:
            yield client
    
    @pytest.fixture
    def auth_headers(client):
        """Generate auth headers for API testing."""
        response = client.post("/api/login", json={
            "username": "test",
            "password": "test"
        })
        token = response.json["token"]
        return {"Authorization": f"Bearer {token}"}
    

    パラメータ化

    基本的なパラメータ化

    @pytest.mark.parametrize("input,expected", [
        ("hello", "HELLO"),
        ("world", "WORLD"),
        ("PyThOn", "PYTHON"),
    ])
    def test_uppercase(input, expected):
        """Test runs 3 times with different inputs."""
        assert input.upper() == expected
    

    複数パラメータ

    @pytest.mark.parametrize("a,b,expected", [
        (2, 3, 5),
        (0, 0, 0),
        (-1, 1, 0),
        (100, 200, 300),
    ])
    def test_add(a, b, expected):
        """Test addition with multiple inputs."""
        assert add(a, b) == expected
    

    ID付きパラメータ化

    @pytest.mark.parametrize("input,expected", [
        ("valid@email.com", True),
        ("invalid", False),
        ("@no-domain.com", False),
    ], ids=["valid-email", "missing-at", "missing-domain"])
    def test_email_validation(input, expected):
        """Test email validation with readable test IDs."""
        assert is_valid_email(input) is expected
    

    パラメータ化フィクスチャ

    @pytest.fixture(params=["sqlite", "postgresql", "mysql"])
    def db(request):
        """Test against multiple database backends."""
        if request.param == "sqlite":
            return Database(":memory:")
        elif request.param == "postgresql":
            return Database("postgresql://localhost/test")
        elif request.param == "mysql":
            return Database("mysql://localhost/test")
    
    def test_database_operations(db):
        """Test runs 3 times, once for each database."""
        result = db.query("SELECT 1")
        assert result is not None
    

    マーカーとテスト選択

    カスタムマーカー

    # Mark slow tests
    @pytest.mark.slow
    def test_slow_operation():
        time.sleep(5)
    
    # Mark integration tests
    @pytest.mark.integration
    def test_api_integration():
        response = requests.get("https://api.example.com")
        assert response.status_code == 200
    
    # Mark unit tests
    @pytest.mark.unit
    def test_unit_logic():
        assert calculate(2, 3) == 5
    

    特定のテストを実行

    # Run only fast tests
    pytest -m "not slow"
    
    # Run only integration tests
    pytest -m integration
    
    # Run integration or slow tests
    pytest -m "integration or slow"
    
    # Run tests marked as unit but not slow
    pytest -m "unit and not slow"
    

    pytest.iniでマーカーを設定

    [pytest]
    markers =
        slow: marks tests as slow
        integration: marks tests as integration tests
        unit: marks tests as unit tests
        django: marks tests as requiring Django
    

    モックとパッチ

    関数のモック

    from unittest.mock import patch, Mock
    
    @patch("mypackage.external_api_call")
    def test_with_mock(api_call_mock):
        """Test with mocked external API."""
        api_call_mock.return_value = {"status": "success"}
    
        result = my_function()
    
        api_call_mock.assert_called_once()
        assert result["status"] == "success"
    

    戻り値のモック

    @patch("mypackage.Database.connect")
    def test_database_connection(connect_mock):
        """Test with mocked database connection."""
        connect_mock.return_value = MockConnection()
    
        db = Database()
        db.connect()
    
        connect_mock.assert_called_once_with("localhost")
    

    例外のモック

    @patch("mypackage.api_call")
    def test_api_error_handling(api_call_mock):
        """Test error handling with mocked exception."""
        api_call_mock.side_effect = ConnectionError("Network error")
    
        with pytest.raises(ConnectionError):
            api_call()
    
        api_call_mock.assert_called_once()
    

    コンテキストマネージャのモック

    @patch("builtins.open", new_callable=mock_open)
    def test_file_reading(mock_file):
        """Test file reading with mocked open."""
        mock_file.return_value.read.return_value = "file content"
    
        result = read_file("test.txt")
    
        mock_file.assert_called_once_with("test.txt", "r")
        assert result == "file content"
    

    Autospec使用

    @patch("mypackage.DBConnection", autospec=True)
    def test_autospec(db_mock):
        """Test with autospec to catch API misuse."""
        db = db_mock.return_value
        db.query("SELECT * FROM users")
    
        # This would fail if DBConnection doesn't have query method
        db_mock.assert_called_once()
    

    クラスインスタンスのモック

    class TestUserService:
        @patch("mypackage.UserRepository")
        def test_create_user(self, repo_mock):
            """Test user creation with mocked repository."""
            repo_mock.return_value.save.return_value = User(id=1, name="Alice")
    
            service = UserService(repo_mock.return_value)
            user = service.create_user(name="Alice")
    
            assert user.name == "Alice"
            repo_mock.return_value.save.assert_called_once()
    

    プロパティのモック

    @pytest.fixture
    def mock_config():
        """Create a mock with a property."""
        config = Mock()
        type(config).debug = PropertyMock(return_value=True)
        type(config).api_key = PropertyMock(return_value="test-key")
        return config
    
    def test_with_mock_config(mock_config):
        """Test with mocked config properties."""
        assert mock_config.debug is True
        assert mock_config.api_key == "test-key"
    

    非同期コードのテスト

    pytest-asyncioを使用した非同期テスト

    import pytest
    
    @pytest.mark.asyncio
    async def test_async_function():
        """Test async function."""
        result = await async_add(2, 3)
        assert result == 5
    
    @pytest.mark.asyncio
    async def test_async_with_fixture(async_client):
        """Test async with async fixture."""
        response = await async_client.get("/api/users")
        assert response.status_code == 200
    

    非同期フィクスチャ

    @pytest.fixture
    async def async_client():
        """Async fixture providing async test client."""
        app = create_app()
        async with app.test_client() as client:
            yield client
    
    @pytest.mark.asyncio
    async def test_api_endpoint(async_client):
        """Test using async fixture."""
        response = await async_client.get("/api/data")
        assert response.status_code == 200
    

    非同期関数のモック

    @pytest.mark.asyncio
    @patch("mypackage.async_api_call")
    async def test_async_mock(api_call_mock):
        """Test async function with mock."""
        api_call_mock.return_value = {"status": "ok"}
    
        result = await my_async_function()
    
        api_call_mock.assert_awaited_once()
        assert result["status"] == "ok"
    

    例外のテスト

    期待される例外のテスト

    def test_divide_by_zero():
        """Test that dividing by zero raises ZeroDivisionError."""
        with pytest.raises(ZeroDivisionError):
            divide(10, 0)
    
    def test_custom_exception():
        """Test custom exception with message."""
        with pytest.raises(ValueError, match="invalid input"):
            validate_input("invalid")
    

    例外属性のテスト

    def test_exception_with_details():
        """Test exception with custom attributes."""
        with pytest.raises(CustomError) as exc_info:
            raise CustomError("error", code=400)
    
        assert exc_info.value.code == 400
        assert "error" in str(exc_info.value)
    

    副作用のテスト

    ファイル操作のテスト

    import tempfile
    import os
    
    def test_file_processing():
        """Test file processing with temp file."""
        with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.txt') as f:
            f.write("test content")
            temp_path = f.name
    
        try:
            result = process_file(temp_path)
            assert result == "processed: test content"
        finally:
            os.unlink(temp_path)
    

    pytestのtmp_pathフィクスチャを使用したテスト

    def test_with_tmp_path(tmp_path):
        """Test using pytest's built-in temp path fixture."""
        test_file = tmp_path / "test.txt"
        test_file.write_text("hello world")
    
        result = process_file(str(test_file))
        assert result == "hello world"
        # tmp_path automatically cleaned up
    

    tmpdirフィクスチャを使用したテスト

    def test_with_tmpdir(tmpdir):
        """Test using pytest's tmpdir fixture."""
        test_file = tmpdir.join("test.txt")
        test_file.write("data")
    
        result = process_file(str(test_file))
        assert result == "data"
    

    テストの整理

    ディレクトリ構造

    tests/
    ├── conftest.py                 # 共有フィクスチャ
    ├── __init__.py
    ├── unit/                       # ユニットテスト
    │   ├── __init__.py
    │   ├── test_models.py
    │   ├── test_utils.py
    │   └── test_services.py
    ├── integration/                # 統合テスト
    │   ├── __init__.py
    │   ├── test_api.py
    │   └── test_database.py
    └── e2e/                        # エンドツーエンドテスト
        ├── __init__.py
        └── test_user_flow.py
    

    テストクラス

    class TestUserService:
        """Group related tests in a class."""
    
        @pytest.fixture(autouse=True)
        def setup(self):
            """Setup runs before each test in this class."""
            self.service = UserService()
    
        def test_create_user(self):
            """Test user creation."""
            user = self.service.create_user("Alice")
            assert user.name == "Alice"
    
        def test_delete_user(self):
            """Test user deletion."""
            user = User(id=1, name="Bob")
            self.service.delete_user(user)
            assert not self.service.user_exists(1)
    

    ベストプラクティス

    すべきこと

    • TDDに従う: コードの前にテストを書く(赤-緑-リファクタリング)
    • 一つのことをテスト: 各テストは単一の動作を検証すべき
    • 説明的な名前を使用: test_user_login_with_invalid_credentials_fails
    • フィクスチャを使用: フィクスチャで重複を排除
    • 外部依存をモック: 外部サービスに依存しない
    • エッジケースをテスト: 空の入力、None値、境界条件
    • 80%以上のカバレッジを目指す: クリティカルパスに焦点を当てる
    • テストを高速に保つ: マークを使用して遅いテストを分離

    してはいけないこと

    • 実装をテストしない: 内部ではなく動作をテスト
    • テストで複雑な条件文を使用しない: テストをシンプルに保つ
    • テスト失敗を無視しない: すべてのテストは通過する必要がある
    • サードパーティコードをテストしない: ライブラリが機能することを信頼
    • テスト間で状態を共有しない: テストは独立すべき
    • テストで例外をキャッチしない: pytest.raisesを使用
    • print文を使用しない: アサーションとpytestの出力を使用
    • 脆弱すぎるテストを書かない: 過度に具体的なモックを避ける

    一般的なパターン

    APIエンドポイントのテスト(FastAPI/Flask)

    @pytest.fixture
    def client():
        app = create_app(testing=True)
        return app.test_client()
    
    def test_get_user(client):
        response = client.get("/api/users/1")
        assert response.status_code == 200
        assert response.json["id"] == 1
    
    def test_create_user(client):
        response = client.post("/api/users", json={
            "name": "Alice",
            "email": "alice@example.com"
        })
        assert response.status_code == 201
        assert response.json["name"] == "Alice"
    

    データベース操作のテスト

    @pytest.fixture
    def db_session():
        """Create a test database session."""
        session = Session(bind=engine)
        session.begin_nested()
        yield session
        session.rollback()
        session.close()
    
    def test_create_user(db_session):
        user = User(name="Alice", email="alice@example.com")
        db_session.add(user)
        db_session.commit()
    
        retrieved = db_session.query(User).filter_by(name="Alice").first()
        assert retrieved.email == "alice@example.com"
    

    クラスメソッドのテスト

    class TestCalculator:
        @pytest.fixture
        def calculator(self):
            return Calculator()
    
        def test_add(self, calculator):
            assert calculator.add(2, 3) == 5
    
        def test_divide_by_zero(self, calculator):
            with pytest.raises(ZeroDivisionError):
                calculator.divide(10, 0)
    

    pytest設定

    pytest.ini

    [pytest]
    testpaths = tests
    python_files = test_*.py
    python_classes = Test*
    python_functions = test_*
    addopts =
        --strict-markers
        --disable-warnings
        --cov=mypackage
        --cov-report=term-missing
        --cov-report=html
    markers =
        slow: marks tests as slow
        integration: marks tests as integration tests
        unit: marks tests as unit tests
    

    pyproject.toml

    [tool.pytest.ini_options]
    testpaths = ["tests"]
    python_files = ["test_*.py"]
    python_classes = ["Test*"]
    python_functions = ["test_*"]
    addopts = [
        "--strict-markers",
        "--cov=mypackage",
        "--cov-report=term-missing",
        "--cov-report=html",
    ]
    markers = [
        "slow: marks tests as slow",
        "integration: marks tests as integration tests",
        "unit: marks tests as unit tests",
    ]
    

    テストの実行

    # Run all tests
    pytest
    
    # Run specific file
    pytest tests/test_utils.py
    
    # Run specific test
    pytest tests/test_utils.py::test_function
    
    # Run with verbose output
    pytest -v
    
    # Run with coverage
    pytest --cov=mypackage --cov-report=html
    
    # Run only fast tests
    pytest -m "not slow"
    
    # Run until first failure
    pytest -x
    
    # Run and stop on N failures
    pytest --maxfail=3
    
    # Run last failed tests
    pytest --lf
    
    # Run tests with pattern
    pytest -k "test_user"
    
    # Run with debugger on failure
    pytest --pdb
    

    クイックリファレンス

    パターン使用法
    pytest.raises()期待される例外をテスト
    @pytest.fixture()再利用可能なテストフィクスチャを作成
    @pytest.mark.parametrize()複数の入力でテストを実行
    @pytest.mark.slow遅いテストをマーク
    pytest -m "not slow"遅いテストをスキップ
    @patch()関数とクラスをモック
    tmp_pathフィクスチャ自動一時ディレクトリ
    pytest --covカバレッジレポートを生成
    assertシンプルで読みやすいアサーション

    覚えておいてください: テストもコードです。それらをクリーンで、読みやすく、保守可能に保ちましょう。良いテストはバグをキャッチし、優れたテストはそれらを防ぎます。

    Alternatives

    Compare before choosing