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
| Plataforma | Comando |
|---|---|
| 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
| Comando | Descripció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 -x | Detener después del primer fallo de prueba |
pytest --maxfail=3 | Detener 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-only | Mostrar qué pruebas se ejecutarían sin ejecutarlas |
pytest --lf | Ejecutar solo pruebas que fallaron en la última ejecución (último fallido) |
pytest --ff | Ejecutar pruebas fallidas primero, luego otras (fallidas primero) |
pytest -l | Mostrar variables locales en trazas de error al fallar |
Uso Avanzado
| Comando | Descripción |
|---|---|
pytest -n auto | Ejecutar pruebas en paralelo usando todos los núcleos de CPU disponibles (requiere pytest-xdist) |
pytest -n 4 | Ejecutar pruebas en paralelo con 4 procesos de trabajo |
pytest --durations=10 | Mostrar las 10 duraciones de pruebas más lentas |
pytest --durations=10 --durations-min=1.0 | Mostrar pruebas más lentas que tarden al menos 1 segundo |
pytest --cov=myproject | Ejecutar pruebas con informe de cobertura de código (requiere pytest-cov) |
pytest --cov=myproject --cov-report=html | Generar informe de cobertura HTML en el directorio htmlcov/ |
pytest --cov=myproject --cov-report=term-missing | Mostrar cobertura con números de línea faltantes en terminal |
pytest --cov=myproject --cov-fail-under=80 | Fallar si la cobertura es inferior al 80% |
pytest --cov-branch | Incluir análisis de cobertura de ramas |
pytest --junitxml=report.xml | Generar informe XML de JUnit para integración de CI/CD |
pytest --html=report.html | Generar informe de pruebas HTML (requiere pytest-html) |
pytest --pdb | Entrar en depurador de Python (PDB) en caso de fallos de pruebas |
pytest --trace | Entrar en PDB al inicio de cada prueba |
pytest --setup-show | Mostrar configuración y desmontaje de fixtures durante la ejecución |
pytest --fixtures | Listar todos los fixtures disponibles y sus docstrings |
pytest --markers | Listar todos los marcadores registrados |
pytest --tb=short | Usar formato de traza más corto |
pytest --tb=line | Mostrar una línea por fallo en la traza |
pytest --tb=no | Desactivar salida de traza |
pytest -W error::DeprecationWarning | Tratar advertencias de deprecación como errores |
pytest --capture=no | Desactivar captura de salida (igual que -s) |
pytest --timeout=300 | Establecer tiempo de espera de 300 segundos por prueba (requiere pytest-timeout) |
pytest --count=3 | Repetir cada prueba 3 veces (requiere pytest-repeat) |
pytest --random-order | Ejecutar pruebas en orden aleatorio (requiere pytest-random-order) |
pytest -ra | Mostrar 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` |