Testing¶
Comandos¶
pytest # Todos
pytest -x # Stop on first failure
pytest -k "test_create" # Por nombre
pytest tests/unit/core/ --tb=short # Solo core
pytest -m "not slow" # Excluir OCR/NER lentos
pytest --cov=src --cov-report=html # Coverage
pytest tests/integration/ -vvs --pdb # Debug interactivo
Markers¶
pytest -m "not slow" # Excluir OCR/NER lentos
pytest -m integration # Solo con BD
pytest -m e2e # Flujo completo (playwright)
Estructura¶
tests/
├── unit/ # Tests aislados (core, application, infrastructure)
│ └── interfaces/api/ # Tests API (FastAPI TestClient)
│ ├── test_api_foundation.py # S24: 19 tests (health, auth, documents)
│ ├── test_api_fase2.py # S25: 18 tests (process, validate, search, duplicates, config)
│ └── test_api_sprint25_1.py # S25.1: 33 tests (security, XSS, JWT, bugs)
├── integration/ # Tests entre capas
├── e2e/ # Flujo completo (playwright)
├── fixtures/ # Datos de test
└── conftest.py # Fixtures pytest globales
Pre-commit (quality gate obligatorio)¶
Integration Tests¶
Ubicación: tests/integration/
Tests cross-layer que verifican la integración real entre capas (API → Application → Persistence):
pytest tests/integration/ -v -m integration # Ejecutar solo integration
pytest tests/integration/ -vvs --pdb # Debug interactivo
Fixtures (tests/integration/conftest.py):
- real_container: ServiceContainer con BD SQLite en memoria (sin mocks)
- real_client: TestClient de FastAPI conectado al container real
- seeded_db: BD con datos de prueba pre-insertados
- Fixture de auth con JWT real para endpoints protegidos
Cobertura: 9+ tests cross-layer verificando flujos completos (create → read → update → delete).
Tests CLI¶
El CLI cuenta con 68+ tests en tests/unit/interfaces/test_cli.py, cubriendo los 20 comandos disponibles incluyendo paths de éxito, error y validación de argumentos.
Metricas actuales¶
- 1707 tests pasando (unit + integration + e2e + security + API)
- 87.77% coverage (CI gate: 88%, excluyendo GUI)
- 16 integration tests (9 API vertical slices + 7 pipeline)
- 19 tests de seguridad base + 33 tests API security (S25.1)
- E2E con playwright (29/32 estables)
- 41 tests Fase 0 (Result pattern, frozen DTOs, JSON serialization)
- 15 tests ServiceContainer Fase 0 (lazy loading, DI, thread safety)
- 84 tests API total (19 S24 + 18 S25 + 33 S25.1 + 14 S28)
Tests Sprint 28 (nuevos)¶
| Archivo | Tests | Cobertura |
|---|---|---|
tests/integration/test_pipeline_integration.py |
7 | Pipeline OCR→NER→Dedup→Persist con mocks |
tests/unit/interfaces/test_cli.py (expandido) |
+15 | cmd_process, cmd_extract_acta, cmd_audit_report, cmd_health, cmd_stats_daily |
tests/unit/persistence/test_sqlite_repository.py (expandido) |
+19 | Range queries, transactions, find_by_field, context manager |
tests/unit/interfaces/api/test_api_sprint28.py |
14 | Duplicates, import_export, auth refresh, config routes |
tests/unit/test_coverage_sprint28.py |
90 | ServiceContainer, active_learning, auth JWT, sanitizers, statistics, dedup_config, main.py |
Tests API (FastAPI TestClient)¶
Pattern para tests API:
# Fixture con auth desactivado y mocks
@pytest.fixture
def client(mock_container, test_settings, task_manager) -> TestClient:
app = create_app()
app.state.container = mock_container
app.state.settings = test_settings
app.state.task_manager = task_manager
with patch("...dependencies.get_settings", return_value=test_settings):
yield TestClient(app, raise_server_exceptions=False)
# Test usa client fixture
def test_endpoint(self, client):
response = client.get("/api/v1/health")
assert response.status_code == 200
Nota: ServiceContainer tests usan type(svc).__name__ == "ClassName" en vez de isinstance() para evitar problemas de import path en pytest.
Desglose tests application/¶
| Archivo | Tests | Scope |
|---|---|---|
test_statistics_service.py |
16 | 8 base B3 + 8 Fase 0 I1 |
test_search_service.py |
28 | 19 base B2 + 9 Fase 0 I2 |
test_validation_service.py |
26 | 14 base B1 + 7 I3 + 5 I5 |
test_manual_entry_service.py |
27 | 10 base B4 + 7 I4 + 5 I6 + 5 dedup |
test_service_container.py |
36 | 21 base + 15 Fase 0 properties |
test_process_document.py |
18 | Pipeline OCR+NER+Dedup |
test_export_excel.py |
41 | Export Excel use case |
test_import_excel.py |
42 | Import Excel use case |
Patron de tests Fase 0 (replicar para Fase 1+)¶
Cada servicio *_result() debe tener:
- Test Success path con mock repository
- Test Failure path con excepcion
- Test FrozenInstanceError en Response DTO
- Test dataclasses.asdict() + json.dumps() (JSON serializable)
- Test backward compat (metodo dict/list original intacto)
Ver TESTING_GUIDE.md para estrategia detallada.