Suite completa de pruebas automatizadas para validar componentes críticos del proyecto MLOps-GPO45.
- Estructura de Tests
- Requisitos
- Instalación
- Ejecución de Tests
- Tipos de Tests
- Cobertura de Código
- Mejores Prácticas
tests/
├── __init__.py # Inicialización del paquete de tests
├── conftest.py # Fixtures compartidos entre tests
├── test_data_reader.py # Tests para DataReader
├── test_data_explorer.py # Tests para DataExplorer
├── test_data_cleaning.py # Tests para DataCleaning ⭐
├── test_data_preprocessing.py # Tests para Preprocessor ⭐
├── test_data_analysis.py # Tests para DataAnalysis
└── test_integration_pipeline.py # Tests de integración end-to-end ⭐
⭐ = Tests prioritarios
pytest>=7.4.0
pytest-cov>=4.1.0 # Para cobertura de código
pytest-xdist>=3.3.1 # Para ejecución paralela (opcional)
pytest-timeout>=2.1.0 # Para timeout de tests (opcional)pip install pytest pytest-cov pytest-xdist pytest-timeoutEjecutar todos los tests:
pytestpytest -vpytest -qPor archivo:
pytest tests/test_data_cleaning.py
pytest tests/test_data_preprocessing.py
pytest tests/test_integration_pipeline.pyPor clase:
pytest tests/test_data_cleaning.py::TestDataCleaningInitialization
pytest tests/test_data_preprocessing.py::TestPreprocessorInitializationPor función específica:
pytest tests/test_data_cleaning.py::TestConvertDataTypes::test_convert_string_to_numericPor patrón de nombre:
pytest -k "cleaning" # Ejecuta tests con "cleaning" en el nombre
pytest -k "test_initialization" # Ejecuta tests de inicializaciónTests unitarios:
pytest -m unitTests de integración:
pytest -m integrationTests rápidos (smoke tests):
pytest -m smokeDetener en el primer fallo:
pytest -xEjecutar último test fallido:
pytest --lfEjecutar tests fallidos primero:
pytest --ffMostrar output completo (print statements):
pytest -sEjecutar en paralelo (requiere pytest-xdist):
pytest -n auto # Usa todos los cores disponibles
pytest -n 4 # Usa 4 workersCon timeout:
pytest --timeout=60Validan funciones y métodos individuales de forma aislada.
Ejemplos:
test_data_cleaning.py: Tests para cada método de DataCleaningtest_data_preprocessing.py: Tests para transformaciones y splitstest_data_reader.py: Tests para lectura de archivos
Ejecutar solo tests unitarios:
pytest tests/test_data_cleaning.py tests/test_data_preprocessing.pyValidan el flujo completo entre múltiples componentes.
Archivo principal:
test_integration_pipeline.py: Tests end-to-end del pipeline completo
Ejecutar tests de integración:
pytest tests/test_integration_pipeline.pyLos fixtures en conftest.py proveen datos de prueba reutilizables:
sample_dataframe: DataFrame limpio de pruebasample_dataframe_with_nulls: DataFrame con valores faltantessample_dataframe_with_duplicates: DataFrame con duplicadossample_dataframe_with_outliers: DataFrame con valores atípicosmock_version_tracker: Mock del VersionTrackertemp_csv_file: Archivo CSV temporal
HTML (recomendado):
pytest --cov=src --cov-report=htmlLuego abrir htmlcov/index.html en el navegador.
Terminal:
pytest --cov=src --cov-report=term-missingCobertura por módulo:
pytest --cov=src.data --cov-report=term| Cobertura | Calificación | Acción Recomendada |
|---|---|---|
| 90-100% | Excelente ✅ | Mantener |
| 75-89% | Buena 👍 | Mejorar áreas críticas |
| 60-74% | Aceptable |
Agregar más tests |
| < 60% | Insuficiente ❌ | Prioridad alta |
- Archivos:
test_<nombre_modulo>.py - Clases:
Test<NombreClase> - Funciones:
test_<descripcion_comportamiento>
def test_nombre_descriptivo(fixture1, fixture2):
"""Docstring explicando qué se está testeando."""
# Arrange (Preparar)
data = prepare_test_data()
# Act (Actuar)
result = function_under_test(data)
# Assert (Verificar)
assert result == expected_valueUsar fixtures de conftest.py en lugar de crear datos en cada test:
def test_with_fixture(sample_dataframe, mock_version_tracker):
cleaner = DataCleaning(sample_dataframe, mock_version_tracker)
# ...Para probar múltiples casos:
@pytest.mark.parametrize("strategy", ['drop', 'mean', 'median'])
def test_missing_values(strategy, sample_dataframe_with_nulls):
# Test con diferentes estrategias
passUsar mocks para evitar dependencias externas:
@patch('dvc.api.get_url')
def test_with_mock(mock_get_url):
mock_get_url.return_value = "fake_url"
# ...# Tests rápidos durante desarrollo
pytest -x -v
# Tests con cobertura
pytest --cov=src --cov-report=term-missing
# Re-ejecutar últimos fallos
pytest --lf# Suite completa con reporte
pytest -v --cov=src --cov-report=html --cov-report=term
# Suite completa en paralelo
pytest -n auto -v# Con output completo
pytest -s -v
# Con debugger (pdb)
pytest --pdb
# Verbose extremo
pytest -vvSolución:
# Agregar el directorio raíz al PYTHONPATH
export PYTHONPATH="${PYTHONPATH}:$(pwd)"
# O instalar el paquete en modo desarrollo
pip install -e .Causa: Los tests están comentados (usando pass).
Solución: Descomentar las líneas del test que desees ejecutar.
Solución: Asegurarse de que conftest.py esté en el directorio tests/.
Solución: Verificar que la fixture esté definida en conftest.py o en el mismo archivo de test.
-
Descomentar Tests: Los tests actuales están como templates. Descomentar los imports y el código de test.
-
Ejecutar Suite Básica:
pytest -v
-
Agregar Tests Específicos: Agregar tests adicionales según necesidades del proyecto.
-
Integrar en CI/CD: Agregar ejecución de tests al pipeline de CI/CD:
# .github/workflows/tests.yml - name: Run tests run: pytest --cov=src --cov-report=xml
-
Monitorear Cobertura: Mantener cobertura > 80% para componentes críticos.
- Todos los tests pasan localmente
- Cobertura > 80% en módulos críticos
- Tests de integración ejecutados exitosamente
- Sin warnings o deprecations
- Documentación de tests actualizada
- Tests agregados al CI/CD
Última actualización: Noviembre 2025
Autor: Equipo MLOps-GPO45
Contacto: [Tu equipo]