Ir al contenido

Hoja de referencia de pytest

pip install pytest``pip install pytest sudo apt install python3-pytest``sudo apt-get install python3-pytest sudo dnf install python3-pytest``sudo dnf install python3-pytest sudo pacman -S python-pytest``sudo pacman -S python-pytest brew install pytest``brew install pytest choco install pytest``choco install pytest python -m venv venv && source venv/bin/activate && pip install pytest``python -m venv venv && source venv/bin/activate && pip install pytest pip install pytest pytest-cov pytest-xdist pytest-mock pytest-html``pip install pytest pytest-cov pytest-sugar pytest --version``pytest --version pytest``pytest pytest test_file.py``pytest test_file.py pytest tests/``pytest test_directory/ pytest test_file.py::test_function``pytest test_file.py::test_function_name pytest test_file.py::TestClass``pytest test_file.py::TestClassName pytest test_file.py::TestClass::test_method``pytest test_file.py::TestClassName::test_method_name pytest -v``pytest -v pytest -vv``pytest -vv pytest -q``pytest -q

Hoja de referencia de pytest

Instalación

PlataformaComando
pip (Todas las plataformas)
Ubuntu/Debian
Fedora/RHEL
Arch Linux
macOS (Homebrew)
Windows (Chocolatey)
Entorno Virtual
Con Plugins Comunes
Verificar Instalación

Comandos Básicos

ComandoDescripción
Ejecutar todas las pruebas en el directorio actual y subdirectorios
Ejecutar pruebas en un archivo específico
Ejecutar todas las pruebas en un directorio específico
Ejecutar una función de prueba específica
Ejecutar todas las pruebas en una clase específica
Ejecutar un método de prueba específico en una clase
Ejecutar pruebas con salida detallada (mostrar nombres de pruebas)
Ejecutar pruebas con salida muy detallada (mostrar detalles completos)
Ejecutar pruebas en modo silencioso (salida mínima)
pytest -xDetener después del primer fallo de prueba
pytest --maxfail=3Detener después de N fallos de prueba
pytest -k "test_user"Ejecutar pruebas que coincidan con la expresión de palabra clave
pytest -k "user and not admin"Ejecutar pruebas que coincidan con múltiples palabras clave (lógica AND/NOT)
pytest -m "slow"Ejecutar pruebas marcadas con un marcador específico
pytest -m "not slow"Ejecutar pruebas excluyendo un marcador específico
pytest --collect-onlyMostrar qué pruebas se ejecutarían sin ejecutarlas
pytest --lfEjecutar solo pruebas que fallaron en la última ejecución (último fallido)
pytest --ffEjecutar pruebas fallidas primero, luego otras (fallidas primero)
pytest -lMostrar variables locales en trazas de error al fallar

Uso Avanzado

ComandoDescripción
pytest -n autoEjecutar pruebas en paralelo usando todos los núcleos de CPU disponibles (requiere pytest-xdist)
pytest -n 4Ejecutar pruebas en paralelo con 4 procesos de trabajo
pytest --durations=10Mostrar las 10 duraciones de pruebas más lentas
pytest --durations=10 --durations-min=1.0Mostrar pruebas más lentas que tarden al menos 1 segundo
pytest --cov=myprojectEjecutar pruebas con informe de cobertura de código (requiere pytest-cov)
pytest --cov=myproject --cov-report=htmlGenerar informe de cobertura HTML en el directorio htmlcov/
pytest --cov=myproject --cov-report=term-missingMostrar cobertura con números de línea faltantes en terminal
pytest --cov=myproject --cov-fail-under=80Fallar si la cobertura es inferior al 80%
pytest --cov-branchIncluir análisis de cobertura de ramas
pytest --junitxml=report.xmlGenerar informe XML de JUnit para integración de CI/CD
pytest --html=report.htmlGenerar informe de pruebas HTML (requiere pytest-html)
pytest --pdbEntrar en depurador de Python (PDB) en caso de fallos de pruebas
pytest --traceEntrar en PDB al inicio de cada prueba
pytest --setup-showMostrar configuración y desmontaje de fixtures durante la ejecución
pytest --fixturesListar todos los fixtures disponibles y sus docstrings
pytest --markersListar todos los marcadores registrados
pytest --tb=shortUsar formato de traza más corto
pytest --tb=lineMostrar una línea por fallo en la traza
pytest --tb=noDesactivar salida de traza
pytest -W error::DeprecationWarningTratar advertencias de deprecación como errores
pytest --capture=noDesactivar captura de salida (igual que -s)
pytest --timeout=300Establecer tiempo de espera de 300 segundos por prueba (requiere pytest-timeout)
pytest --count=3Repetir cada prueba 3 veces (requiere pytest-repeat)
pytest --random-orderEjecutar pruebas en orden aleatorio (requiere pytest-random-order)
pytest -raMostrar resumen breve de pruebas para todas las pruebas (pasadas, fallidas, omitidas, etc.)

Configuración

Archivo de configuración pytest.ini

Colocar en el directorio raíz del proyecto:

[pytest]
# Minimum pytest version required
minversion = 7.0

# Directories to search for tests
testpaths = tests

# Test file patterns
python_files = test_*.py *_test.py

# Test class patterns
python_classes = Test* *Tests

# Test function patterns
python_functions = test_*

# Default command line options
addopts = 
    -ra
    --strict-markers
    --strict-config
    --verbose
    --cov=myproject
    --cov-report=html
    --cov-report=term-missing

# Custom markers
markers =
    slow: marks tests as slow (deselect with '-m "not slow"')
    integration: marks tests as integration tests
    unit: marks tests as unit tests
    smoke: marks tests as smoke tests
    database: marks tests requiring database connection
    api: marks tests for API testing

# Directories to ignore
norecursedirs = .git .tox dist build *.egg venv node_modules

# Warning filters
filterwarnings =
    error
    ignore::UserWarning
    ignore::DeprecationWarning

# Logging configuration
log_cli = true
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)s] %(message)s
log_cli_date_format = %Y-%m-%d %H:%M:%S

Configuración pyproject.toml

Proyectos de Python modernos usando pyproject.toml:

[tool.pytest.ini_options]
minversion = "7.0"
testpaths = ["tests"]
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]

addopts = [
    "-ra",
    "--strict-markers",
    "--cov=myproject",
    "--cov-branch",
    "--cov-report=html",
    "--cov-report=term-missing:skip-covered",
    "--cov-fail-under=80",
]

markers = [
    "slow: marks tests as slow",
    "integration: integration tests",
    "unit: unit tests",
    "smoke: smoke tests",
]

filterwarnings = [
    "error",
    "ignore::UserWarning",
]

conftest.py - Fixtures compartidos

Colocar en el directorio raíz de pruebas para fixtures compartidos:

import pytest

# Session-scoped fixture (runs once per test session)
@pytest.fixture(scope="session")
def database():
    """Provide database connection for entire test session"""
    db = create_database_connection()
    yield db
    db.close()

# Module-scoped fixture (runs once per test module)
@pytest.fixture(scope="module")
def api_client():
    """Provide API client for test module"""
    client = APIClient()
    yield client
    client.cleanup()

# Function-scoped fixture (default, runs for each test)
@pytest.fixture
def sample_data():
    """Provide sample data for testing"""
    return {"id": 1, "name": "Test User"}

# Autouse fixture (automatically used by all tests)
@pytest.fixture(autouse=True)
def reset_state():
    """Reset application state before each test"""
    clear_cache()
    yield
    cleanup_resources()

# Parametrized fixture
@pytest.fixture(params=["sqlite", "postgres", "mysql"])
def db_type(request):
    """Test with multiple database types"""
    return request.param

# Configure pytest hooks
def pytest_configure(config):
    """Add custom configuration"""
    config.addinivalue_line(
        "markers", "custom: custom marker description"
    )

Casos de Uso Comunes

Caso de Uso 1: Pruebas Unitarias Básicas

# Create test file
cat > test_calculator.py << 'EOF'
def add(a, b):
    return a + b

def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0
    assert add(0, 0) == 0
EOF

# Run the tests
pytest test_calculator.py -v

Caso de Uso 2: Pruebas con Fixtures```bash

Create test with fixtures

cat > test_user.py << ‘EOF’ import pytest

@pytest.fixture def user_data(): return {“username”: “testuser”, “email”: “test@example.com”}

def test_user_creation(user_data): assert user_data[“username”] == “testuser” assert ”@” in user_data[“email”] EOF

Run tests with fixture details

pytest test_user.py -v —setup-show

```bash
# Create parametrized tests
cat > test_math.py << 'EOF'
import pytest

@pytest.mark.parametrize("input,expected", [
    (2, 4),
    (3, 9),
    (4, 16),
    (5, 25),
])
def test_square(input, expected):
    assert input ** 2 == expected
EOF

# Run parametrized tests
pytest test_math.py -v
```### Caso de Uso 4: Pruebas de Integración con Marcadores
```bash
# Create tests with markers
cat > test_api.py << 'EOF'
import pytest

@pytest.mark.unit
def test_data_validation():
    assert True

@pytest.mark.integration
def test_api_endpoint():
    # Simulated API test
    assert True

@pytest.mark.slow
@pytest.mark.integration
def test_full_workflow():
    # Long-running test
    assert True
EOF

# Run only unit tests
pytest test_api.py -m unit -v

# Run integration tests excluding slow ones
pytest test_api.py -m "integration and not slow" -v
```### Caso de Uso 5: Generación de Informe de Cobertura
```bash
# Run tests with coverage and generate reports
pytest --cov=myproject --cov-report=html --cov-report=term-missing

# View coverage report
# HTML report will be in htmlcov/index.html

# Run with coverage threshold
pytest --cov=myproject --cov-fail-under=80

# Generate coverage badge
pytest --cov=myproject --cov-report=term --cov-report=html
```## Mejores Prácticas
`test_`- **Usar nombres de pruebas descriptivos**: Nombrar pruebas con `test_user_registration_with_valid_email`prefijo y describir lo que prueban (por ejemplo, )
- **Seguir el patrón AAA**: Estructurar pruebas con secciones de Arrange (preparación), Act (ejecución), Assert (verificación) para mayor claridad
- **Usar fixtures para configuración/limpieza**: Aprovechar fixtures de pytest en lugar de métodos de setup/teardown para mejor reutilización e inyección de dependencias
- **Marcar pruebas apropiadamente**: Usar marcadores (`@pytest.mark.slow`, `@pytest.mark.integration`) para categorizar pruebas y permitir ejecución selectiva
- **Mantener pruebas aisladas**: Cada prueba debe ser independiente y no depender del estado de otras pruebas; usar fixtures con ámbitos apropiados
- **Usar parametrize para pruebas similares**: En lugar de escribir múltiples pruebas similares, usar `@pytest.mark.parametrize`para probar múltiples entradas
- **Configurar pytest.ini o pyproject.toml**: Establecer valores predeterminados de proyecto para descubrimiento de pruebas, marcadores y opciones de línea de comandos en archivos de configuración
- **Escribir aserciones enfocadas**: Usar aserciones simples y claras; la introspección de pytest muestra automáticamente información detallada de fallos
- **Usar conftest.py para fixtures compartidos**: Colocar fixtures reutilizables en archivos `conftest.py`en los niveles de directorio apropiados
- **Ejecutar pruebas frecuentemente**: Ejecutar pruebas durante el desarrollo con `pytest -x`para detenerse en el primer fallo para retroalimentación más rápida
- **Monitorear cobertura de pruebas**: Revisar regularmente informes de cobertura y apuntar a 80%+ de cobertura, pero enfocarse en pruebas significativas sobre porcentaje

## Resolución de Problemas

| Problema | Solución |
|-------|----------|
| **Pruebas no descubiertas** | Asegurar que archivos coincidan con patrones: `test_*.py`o `*_test.py`, funciones inicien con `test_`, clases inicien con `Test`|
| **Errores de importación en pruebas** | Añadir archivos `__init__.py`vacíos en directorios de pruebas, o instalar paquete en modo editable: `pip install -e .`|
| **Fixture no encontrado** | Verificar que el fixture esté definido en el mismo archivo o `conftest.py`, verificar ámbito correcto, asegurar que el nombre del fixture coincida con el parámetro |
| **Pruebas pasan localmente pero fallan en CI** | Verificar dependencias específicas del entorno, asegurar versiones de Python consistentes, verificar todas las dependencias en `requirements.txt`|
| **Ejecución lenta de pruebas** | Usar `pytest --durations=10`para identificar pruebas lentas, considerar ejecución paralela con`pytest -n auto`, marca las pruebas lentas con`@pytest.mark.slow`|
| **La cobertura no funciona** | Instala pytest-cov:`pip install pytest-cov`, asegúrate de que la ruta de origen sea correcta:`--cov=myproject`, verifica`.coveragerc`configuración |
| **Marcadores no reconocidos** | Registra marcadores en`pytest.ini`o`pyproject.toml`bajo`[tool.pytest.ini_options]`, usa`--strict-markers`para detectar errores tipográficos |
| **PDB no funciona con captura** | Usa`pytest -s --pdb`para deshabilitar la captura de salida, o usa`pytest.set_trace()`en lugar de`pdb.set_trace()`|
| **Fixtures ejecutándose en orden incorrecto** | Verifica el alcance del fixture (sesión > módulo > clase > función), usa`@pytest.fixture(autouse=True)`con cuidado, revisa la cadena de dependencias |
| **Pruebas paralelas fallando** | Asegúrate de que las pruebas estén aisladas y no compartan estado, verifica condiciones de carrera, usa bloqueo adecuado para recursos compartidos |
| **Fugas de memoria en pruebas** | Usa`@pytest.fixture(scope="function")`para limpieza adecuada, asegúrate de que los fixtures liberen y limpien correctamente, verifica referencias circulares |
| **Advertencias saturando la salida** | Configura filtros de advertencia en`pytest.ini`:`filterwarnings = ignore::DeprecationWarning`, o usa`-W`bandera: |`pytest -W ignore::UserWarning` |