Implement structured Python tests using Pytest patterns like fixtures, markers, and mocks.

Install

mkdir -p .claude/skills/pytest && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/2282" && unzip -o skill.zip -d .claude/skills/pytest && rm skill.zip

Installs to .claude/skills/pytest

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Pytest testing patterns for Python. Trigger: When writing or refactoring pytest tests (fixtures, mocking, parametrize, markers). For Prowler-specific API/SDK testing conventions, also use prowler-test-api or prowler-test-sdk.
225 chars · catalog description✓ has a “when” trigger
Intermediate

Key capabilities

  • Structure unit tests with fixture dependencies
  • Implement parametrize for data-driven testing
  • Create scoped setup and teardown routines
  • Mock external service dependencies

How it works

Applies established pytest patterns (fixtures, mocks, parametrize) to structure and clean up automated test suites.

Inputs & outputs

You give it
Target Python function or class
You get back
Pytest-compliant test file

When to use pytest

  • Write unit tests for Python functions
  • Create reusable fixtures
  • Implement mock objects for dependencies

About this skill

Basic Test Structure

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")

Fixtures

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)

Mocking

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"

Parametrize

@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

Markers

# 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"

Async Tests

import pytest

@pytest.mark.asyncio
async def test_async_function():
    result = await async_fetch_data()
    assert result is not None

Commands

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

References

For general pytest documentation, see:

For Prowler SDK testing with provider-specific patterns (moto, MagicMock), see:

When not to use it

  • Non-Python testing projects
  • Functional/Integration tests better suited for Selenium

Prerequisites

pytest

Limitations

  • Dependent on test coverage quality
  • Requires knowledge of mocking boundaries

How it compares

Provides domain-specific test structuring rather than basic Python boilerplate code.

Compared to similar skills

pytest side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
pytest (this skill)87moReviewIntermediate
python-testing-patterns772moReviewIntermediate
pr-review62moReviewIntermediate
code-change-verification44moReviewBeginner

Try saying

Example prompts that trigger this skill in your AI assistant.

Search skills

Search the agent skills registry