[pytest]# Minimum pytest version requiredminversion=7.0# Directories to search for teststestpaths=tests# Test file patternspython_files=test_*.py *_test.py# Test class patternspython_classes=Test* *Tests# Test function patternspython_functions=test_*# Default command line optionsaddopts=-ra--strict-markers--strict-config--verbose--cov=myproject--cov-report=html--cov-report=term-missing# Custom markersmarkers=slow:marks tests as slow (deselect with '-m "not slow"')integration:marks tests as integration testsunit:marks tests as unit testssmoke:marks tests as smoke testsdatabase:marks tests requiring database connectionapi:marks tests for API testing# Directories to ignorenorecursedirs=.git .tox dist build *.egg venv node_modules# Warning filtersfilterwarnings=errorignore::UserWarningignore::DeprecationWarning# Logging configurationlog_cli=truelog_cli_level=INFOlog_cli_format=%(asctime)s [%(levelname)s] %(message)slog_cli_date_format=%Y-%m-%d %H:%M:%S
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",]
Colocar en el directorio raíz de pruebas para fixtures compartidos:
importpytest# Session-scoped fixture (runs once per test session)@pytest.fixture(scope="session")defdatabase():"""Provide database connection for entire test session"""db=create_database_connection()yielddbdb.close()# Module-scoped fixture (runs once per test module)@pytest.fixture(scope="module")defapi_client():"""Provide API client for test module"""client=APIClient()yieldclientclient.cleanup()# Function-scoped fixture (default, runs for each test)@pytest.fixturedefsample_data():"""Provide sample data for testing"""return{"id":1,"name":"Test User"}# Autouse fixture (automatically used by all tests)@pytest.fixture(autouse=True)defreset_state():"""Reset application state before each test"""clear_cache()yieldcleanup_resources()# Parametrized fixture@pytest.fixture(params=["sqlite","postgres","mysql"])defdb_type(request):"""Test with multiple database types"""returnrequest.param# Configure pytest hooksdefpytest_configure(config):"""Add custom configuration"""config.addinivalue_line("markers","custom: custom marker description")
Caso de Uso 4: Pruebas de Integración con Marcadores¶
# Create tests with markerscat>test_api.py<< 'EOF'import pytest@pytest.mark.unitdef test_data_validation(): assert True@pytest.mark.integrationdef test_api_endpoint(): # Simulated API test assert True@pytest.mark.slow@pytest.mark.integrationdef test_full_workflow(): # Long-running test assert TrueEOF# Run only unit testspytesttest_api.py-munit-v
# Run integration tests excluding slow onespytesttest_api.py-m"integration and not slow"-v
Caso de Uso 5: Generación de Informe de Cobertura¶
# Run tests with coverage and generate reportspytest--cov=myproject--cov-report=html--cov-report=term-missing
# View coverage report# HTML report will be in htmlcov/index.html# Run with coverage thresholdpytest--cov=myproject--cov-fail-under=80# Generate coverage badgepytest--cov=myproject--cov-report=term--cov-report=html
Usar nombres de pruebas descriptivos: Nombrar pruebas con test_prefijo y describir lo que prueban (por ejemplo, test_user_registration_with_valid_email)
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 configuración/limpieza 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.parametrizepara 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.pyen los niveles de directorio apropiados
Ejecutar pruebas frecuentemente: Ejecutar pruebas durante el desarrollo con pytest -xpara 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 el porcentaje
Register markers in pytest.ini or pyproject.toml under [tool.pytest.ini_options], use --strict-markers to catch typos
PDB not working with capture
Use pytest -s --pdb to disable output capturing, or use pytest.set_trace() instead of pdb.set_trace()
Fixtures running in wrong order
Check fixture scope (session > module > class > function), use @pytest.fixture(autouse=True) carefully, review dependency chain
Parallel tests failing
Asegúrate de que las pruebas estén aisladas y no compartan estado, verifica las condiciones de carrera, usa bloqueos adecuados para recursos compartidos
Memory leaks in tests
Use @pytest.fixture(scope="function") for proper cleanup, ensure fixtures yield and cleanup properly, check for circular references