Claude
Skills
Sign in
Back

pytest

Included with Lifetime
$97 forever

Advanced Python unit testing framework for customer support tech enablement, covering FastAPI, SQLAlchemy, PostgreSQL, async operations, mocking, fixtures, parametrization, coverage, and comprehensive testing strategies for backend support systems

Backend & APIspythontestingpytestunit-testingfastapisqlalchemypostgresqlmocking

What this skill does


# pytest - Advanced Python Unit Testing for Customer Support

## Overview

pytest is the industry-standard testing framework for Python applications, offering powerful features that enable comprehensive, maintainable, and scalable test suites. This skill focuses specifically on customer support tech enablement, providing patterns and practices for testing backend support systems, ticketing platforms, knowledge bases, and customer data platforms.

Customer support systems require rigorous testing due to their mission-critical nature. Downtime or bugs directly impact customer satisfaction, agent productivity, and business operations. This skill provides comprehensive guidance on testing all aspects of support systems using pytest.

## Why pytest for Customer Support Systems

### Unique Requirements

Customer support applications have specific testing needs:

1. **High Reliability**: Support systems are mission-critical; failures directly affect customer experience
2. **Complex Data Relationships**: Tickets, customers, agents, comments, attachments, and knowledge articles
3. **External Integrations**: Email services (SendGrid, AWS SES), CRM systems (Salesforce, HubSpot), payment processors
4. **Async Operations**: Background jobs, email queues, notification services, webhook deliveries
5. **Data Validation**: Strict validation for customer PII, ticket priorities, SLA requirements, escalation rules
6. **Multi-tenancy**: Isolation between different customer organizations or workspaces
7. **API-First Design**: RESTful APIs requiring comprehensive endpoint coverage
8. **Real-time Features**: WebSocket connections, live chat, real-time ticket updates
9. **Compliance**: GDPR, CCPA, data retention policies, audit logging

### pytest Advantages

pytest addresses these needs through:

- **Powerful Fixture System**: Manage complex database setups, API clients, and test data
- **Parametrization**: Test multiple scenarios efficiently (various ticket types, priority levels, user roles)
- **Rich Plugin Ecosystem**: pytest-asyncio for async testing, pytest-mock for mocking, pytest-cov for coverage
- **Excellent Integration**: Works seamlessly with FastAPI, SQLAlchemy, PostgreSQL, Pydantic
- **Clear Output**: Readable test results and comprehensive error reporting
- **Scalability**: Handles small test suites to thousands of tests with parallel execution
- **Flexibility**: Supports unit, integration, and end-to-end testing in one framework

## Core Competencies

### 1. Fixtures and Dependency Injection

Fixtures are pytest's killer feature, providing reusable setup/teardown logic and dependency injection. For customer support systems, fixtures manage databases, API clients, test data, and external service mocks.

#### Basic Fixtures

```python
import pytest
from app.models import Ticket, Customer, Agent

@pytest.fixture
def support_ticket():
    """Provide a basic support ticket dictionary."""
    return {
        "id": 1,
        "title": "Cannot access account",
        "description": "User unable to login after password reset",
        "status": "open",
        "priority": "high",
        "customer_email": "[email protected]",
        "category": "authentication"
    }

def test_ticket_structure(support_ticket):
    """Test ticket has required fields."""
    assert support_ticket["status"] == "open"
    assert support_ticket["priority"] in ["low", "medium", "high", "critical"]
    assert "@" in support_ticket["customer_email"]
```

#### Fixture Scopes

Control when fixtures are created and destroyed using scopes:

- **function** (default): Created once per test function, destroyed after test completes
- **class**: Created once per test class, shared across all methods
- **module**: Created once per module file, shared across all tests in file
- **package**: Created once per package, shared across all tests in package
- **session**: Created once per entire test session, shared across all tests

```python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
from typing import Generator

@pytest.fixture(scope="session")
def database_engine():
    """Create database engine once per session."""
    engine = create_engine(
        "postgresql://support_user:password@localhost/support_test",
        echo=False,
        pool_pre_ping=True,
        pool_size=10,
        max_overflow=20
    )
    # Create all tables
    from app.database import Base
    Base.metadata.create_all(engine)

    yield engine

    # Cleanup: drop all tables and dispose engine
    Base.metadata.drop_all(engine)
    engine.dispose()

@pytest.fixture(scope="function")
def db_session(database_engine) -> Generator[Session, None, None]:
    """Create a new database session for each test with automatic rollback."""
    SessionLocal = sessionmaker(bind=database_engine)
    session = SessionLocal()

    try:
        yield session
    finally:
        session.rollback()  # Rollback any changes
        session.close()
```

#### Autouse Fixtures

Fixtures that run automatically without being explicitly requested:

```python
@pytest.fixture(autouse=True)
def reset_caches():
    """Clear all caches before each test."""
    from app.cache import ticket_cache, customer_cache, agent_cache
    ticket_cache.clear()
    customer_cache.clear()
    agent_cache.clear()
    yield
    # Optional cleanup after test
    ticket_cache.clear()
    customer_cache.clear()
    agent_cache.clear()

@pytest.fixture(autouse=True, scope="session")
def configure_logging():
    """Configure logging for test session."""
    import logging
    logging.basicConfig(level=logging.WARNING)
    logging.getLogger("sqlalchemy.engine").setLevel(logging.ERROR)
```

#### Fixture Dependencies and Composition

Fixtures can depend on other fixtures, creating dependency chains:

```python
@pytest.fixture
def database_url():
    """Provide database URL for testing."""
    return "postgresql://test:test@localhost:5432/support_test"

@pytest.fixture
def engine(database_url):
    """Create SQLAlchemy engine from database URL."""
    from sqlalchemy import create_engine
    return create_engine(database_url, echo=False)

@pytest.fixture
def session(engine):
    """Create database session from engine."""
    from sqlalchemy.orm import sessionmaker
    Session = sessionmaker(bind=engine)
    session = Session()
    yield session
    session.close()

@pytest.fixture
def sample_customer(session):
    """Create a sample customer using database session."""
    customer = Customer(
        email="[email protected]",
        name="Test Customer",
        tier="premium",
        company="Acme Corp"
    )
    session.add(customer)
    session.commit()
    return customer

@pytest.fixture
def sample_ticket(session, sample_customer):
    """Create a sample ticket linked to sample customer."""
    ticket = Ticket(
        title="Test Ticket",
        description="Test description",
        priority="high",
        status="open",
        customer_id=sample_customer.id
    )
    session.add(ticket)
    session.commit()
    return ticket
```

#### Factory Fixtures

Create fixtures that return factory functions for flexible test data creation:

```python
@pytest.fixture
def ticket_factory(db_session):
    """Factory for creating tickets with custom attributes."""
    created_tickets = []

    def _create_ticket(
        title="Default Ticket",
        description="Default description",
        priority="medium",
        status="open",
        **kwargs
    ):
        ticket = Ticket(
            title=title,
            description=description,
            priority=priority,
            status=status,
            **kwargs
        )
        db_session.add(ticket)
        db_session.commit()
        created_tickets.append(ticket)
        return ticket

    yield _create_ticket

    # Cleanup: delete all created tickets
    for ticket in created_tickets:
        db_session.delete(ticket)
    db_session.commit()

def test_multiple_tickets(ticket_

Related in Backend & APIs