Skip to content
Back to skills

Python Testing

ASecurity

Python testing patterns with pytest including unit tests, integration tests, fixtures, mocking, and coverage. Use when writing Python tests.

  • 8 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 1, 2026
ai-agentspythonsqlfastapitestingapidatabase

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 1, 2026

npx -y skills add DmitriyYukhanov/claude-plugins --skill python-testing --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Python Testing?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Python Testing
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/dmitriyyukhanov-python-testing/badge)](https://www.skillsdirectory.com/skills/dmitriyyukhanov-python-testing)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: python-testing
description: Python testing patterns with pytest including unit tests, integration tests, fixtures, mocking, and coverage. Use when writing Python tests.
---

# Python Testing Skill

You are a testing specialist for Python projects.

## Testing Framework

### Framework Detection
- `conftest.py` or `pytest.ini` → pytest
- `[tool.pytest.ini_options]` in `pyproject.toml` → pytest
- `unittest` imports → unittest (suggest migrating to pytest)
- `tox.ini` → tox runner
- `nox` → nox runner

## Test Distribution

- **~75% Unit Tests**: Fast, mocked dependencies
- **~20% Integration Tests**: Database, API interactions
- **~5% E2E Tests**: Full workflows

## Unit Test Patterns

### Arrange-Act-Assert with Fixtures
```python
import pytest
from unittest.mock import Mock, AsyncMock, patch

class TestUserService:
    @pytest.fixture
    def mock_repository(self) -> Mock:
        return Mock(spec=UserRepository)

    @pytest.fixture
    def service(self, mock_repository: Mock) -> UserService:
        return UserService(mock_repository)

    def test_get_user_returns_user_when_exists(
        self, service: UserService, mock_repository: Mock
    ) -> None:
        # Arrange
        expected_user = User(id="1", name="Test", email="test@example.com")
        mock_repository.find_by_id.return_value = expected_user

        # Act
        result = service.get_user("1")

        # Assert
        assert result == expected_user
        mock_repository.find_by_id.assert_called_once_with("1")

    def test_get_user_returns_none_when_not_exists(
        self, service: UserService, mock_repository: Mock
    ) -> None:
        # Arrange
        mock_repository.find_by_id.return_value = None

        # Act
        result = service.get_user("unknown")

        # Assert
        assert result is None
```

### Parametrized Tests
```python
@pytest.mark.parametrize("input_value,expected", [
    ("hello", "HELLO"),
    ("", ""),
    ("Hello World", "HELLO WORLD"),
])
def test_to_uppercase(input_value: str, expected: str) -> None:
    assert to_uppercase(input_value) == expected
```

### Mocking Strategies
```python
# Mock with spec for type safety
mock_repo = Mock(spec=UserRepository)

# Patch module-level dependencies
with patch("myapp.services.requests.get") as mock_get:
    mock_get.return_value.json.return_value = {"id": "1"}
    result = fetch_user("1")

# AsyncMock for async functions
mock_client = AsyncMock(spec=HttpClient)
mock_client.get.return_value = {"data": "value"}
```

## Async Testing

Use the async plugin configured by the project (`pytest-asyncio` or `pytest-anyio`).

> **Note:** Examples below use `@pytest.mark.asyncio` (pytest-asyncio). If the project uses pytest-anyio, replace with `@pytest.mark.anyio`.

```python
import pytest
from unittest.mock import AsyncMock

@pytest.mark.asyncio
async def test_async_fetch() -> None:
    mock_session = AsyncMock()
    mock_session.get.return_value.__aenter__.return_value.json = AsyncMock(
        return_value={"id": "1"}
    )

    result = await fetch_data(mock_session, "http://example.com")
    assert result == {"id": "1"}
```

## Integration Test Patterns

### Database Tests
```python
@pytest.fixture
async def db_session():
    """Create a test database session."""
    async with async_engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    async with AsyncSession(async_engine) as session:
        yield session

    async with async_engine.begin() as conn:
        await conn.run_sync(Base.metadata.drop_all)

@pytest.mark.asyncio
async def test_create_and_fetch_user(db_session: AsyncSession) -> None:
    repo = SqlAlchemyUserRepository(db_session)
    user = User(name="Test", email="test@example.com")

    await repo.save(user)
    fetched = await repo.find_by_id(user.id)

    assert fetched is not None
    assert fetched.name == "Test"
```

### API Tests (FastAPI)
```python
from fastapi.testclient import TestClient

@pytest.fixture
def client() -> TestClient:
    return TestClient(app)

def test_create_user(client: TestClient) -> None:
    response = client.post("/users", json={"name": "Test", "email": "test@example.com"})
    assert response.status_code == 201
    assert response.json()["name"] == "Test"
```

## Conftest Patterns

```python
# conftest.py - shared fixtures
import pytest

@pytest.fixture(scope="session")
def app_config() -> Config:
    """Application config for tests."""
    return Config(api_url="http://test", timeout=5, debug=True)

@pytest.fixture
def temp_dir(tmp_path: "Path") -> "Path":
    """Temporary directory for file tests."""
    return tmp_path
```

## Coverage Guidelines

- Enforce ≥80% coverage on critical business logic
- Don't chase 100% - focus on meaningful tests
- Use `pytest-cov` for coverage reports
- Never commit real `.env` files or API keys in tests
- Use test fixtures for complex data structures

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.