1. Testing
Estrategias y herramientas para validar que el software funciona correctamente en todos los niveles: unitario, integración, E2E y performance.
1.1 🎯 ¿Por qué Testing?
Por qué: Tests automatizados son la red de seguridad que permite refactorizar, escalar y desplegar con confianza. Sin tests, cada cambio es un riesgo.
Quién: Developers (unitarios, integración), QA (E2E, exploratorio), DevOps (smoke tests, performance).
Costo: Inversión 30% del tiempo de desarrollo, reduce bugs en producción 90%.
1.2 🏗️ Pirámide de Testing
/\
/ \ E2E (pocas, lentas, costosas)
/----\
/ Integ\ Integration (moderadas)
/--------\
/ Unit \ Unit (muchas, rápidas, baratas)
/____________\
Regla 70-20-10:
- 70% tests unitarios
- 20% tests de integración
- 10% tests E2E
1.3 🧪 Testing por Contexto
1.3.1 Backend Testing
Qué: Validar lógica de negocio, persistencia, APIs y servicios.
| Tipo | Qué | Por qué | Cuándo | Dónde | Cómo | Herramientas |
|---|---|---|---|---|---|---|
| Unitarios | Testear funciones/clases aisladas | Rápidos, debuggables, diseño modular | Toda lógica de negocio | Servicios, utilidades, parsers | Mockear dependencias externas, un assert por concepto | JUnit 5, pytest, Jest |
| Integración | Validar interacción entre componentes | Detecta problemas en límites (DB, APIs) | Repositorios, clientes HTTP, colas | Capa de persistencia, integraciones | Usar DB de test (Testcontainers), levantar servicios reales | Testcontainers, pytest-django |
| Mocks | Reemplazar dependencias con dobles | Aislar unidad bajo test, tests deterministas | Cuando dependencia es lenta/impredecible | APIs externas, email, jobs async | Verificar llamadas, stubbar respuestas | Mockito, unittest.mock |
| Cobertura | Medir % de código ejecutado por tests | Identificar código no testeado | CI/CD pipeline, pre-merge | Todo el codebase | Meta: ≥80% en lógica crítica, 60% general | JaCoCo, Coverage.py |
| API Testing | Validar contratos REST/GraphQL | Detectar breaking changes | Cada endpoint público | Controllers, resolvers | Testear happy path + edge cases + errores | Postman, Bruno, REST Assured |
1.3.2 Frontend Testing
Qué: Validar componentes, interacciones de usuario y flujos completos en browsers.
| Tipo | Qué | Por qué | Cuándo | Dónde | Cómo | Herramientas |
|---|---|---|---|---|---|---|
| Unitarios | Testear componentes aislados | Rápidos, validan lógica de presentación | Componentes reutilizables, hooks custom | Componentes sin deps externas | Renderizar con props mockeadas, verificar output | Vitest, Jest, Testing Library |
| Integración | Testear composición de componentes | Validan flujo entre componentes | Páginas, features completas | Módulos/páginas | Renderizar árbol de componentes, interactuar con DOM | Testing Library, Enzyme |
| E2E | Testear flujos en browser real | Validan experiencia real de usuario | Flujos críticos (login, checkout, pago) | Toda la app + backend | Automatizar clicks, inputs, navegación | Playwright, Cypress |
| Visual Regression | Detectar cambios visuales no deseados | Previene bugs de CSS/layout | Componentes de UI library | Storybook, componentes aislados | Comparar screenshots antes/después | Chromatic, Percy |
| Accesibilidad | Validar WCAG compliance | Inclusión, cumplimiento legal | Todos los componentes interactivos | Formularios, modales, navegación | Validar roles ARIA, contraste, keyboard nav | axe-core, jest-axe |
1.3.3 Mobile Testing
Qué: Validar apps nativas e híbridas en dispositivos reales y emuladores.
| Tipo | Qué | Por qué | Cuándo | Dónde | Cómo | Herramientas |
|---|---|---|---|---|---|---|
| Unitarios | Lógica de negocio en app | Rápidos, sin UI | ViewModels, servicios, parsers | Lógica separada de UI | Mockear platform APIs | XCTest, JUnit |
| UI Testing | Flujos de usuario en emulador | Validan interacción real | Flujos críticos de la app | Pantallas principales | Automatizar taps, swipes, inputs | Espresso (Android), XCUITest (iOS) |
| Cross-platform | Testing multiplataforma | Un código para iOS + Android | Apps híbridas (React Native, Flutter) | Toda la app | Scripts que corren en ambos OS | Appium, Detox |
| Device Farm | Testing en dispositivos reales | Detecta bugs específicos de device | Antes de release | Toda la app | Subir APK/IPA, ejecutar tests remotamente | AWS Device Farm, BrowserStack |
1.3.4 Performance Testing
Qué: Medir latencia, throughput y estabilidad bajo carga.
| Tipo | Qué | Por qué | Cuándo | Dónde | Cómo | Herramientas |
|---|---|---|---|---|---|---|
| Load Testing | Simular usuarios concurrentes | Validar SLOs (p95 < 500ms) | Antes de lanzar feature, quarterly | Endpoints críticos | Rampa de usuarios, medir latencia/errores | k6, Gatling, Locust |
| Stress Testing | Llevar sistema al límite | Encontrar punto de quiebre | Capacity planning | Todo el sistema | Aumentar carga hasta fallos | Artillery, JMeter |
| Spike Testing | Picos súbitos de tráfico | Validar auto-scaling, circuit breakers | Sistemas con tráfico variable | Load balancers, caches | Enviar 10x tráfico normal repentinamente | k6, Gatling |
| Soak Testing | Carga sostenida por horas/días | Detectar memory leaks, degradación | Sistemas 24/7 | Backend services | Carga constante 8-48 horas, monitorear memoria | k6, Locust |
1.4 🧪 Testing Avanzado
| Tipo | Qué | Por qué | Cuándo | Dónde | Cómo | Herramientas |
|---|---|---|---|---|---|---|
| Contract Testing | Validar contratos entre servicios | Evita breaking changes | Microservicios, APIs públicas | Provider-Consumer | Consumer define expectativas (Pact), Provider valida | Pact, Spring Cloud Contract |
| Mutation Testing | Validar calidad de tests mutando código | Tests débiles no detectan bugs reales | Lógica crítica con alta cobertura | Algoritmos, validadores | Cambiar > por >=, && por \|\|, verificar tests fallen |
Stryker, mutmut |
| Chaos Engineering | Inyectar fallos para validar resiliencia | Validar que el sistema tolera fallos reales | Sistemas distribuidos críticos | Infraestructura | Ver Capítulo 38 - Chaos Engineering para detalles completos | Ver Capítulo 38 |
| Snapshot Testing | Guardar output como referencia | Detectar cambios no intencionados | Componentes estables, APIs | UI components, JSON responses | Primera ejecución guarda snapshot, siguientes comparan | Jest Snapshots, pytest-regressions |
| Smoke Testing | Validar funcionalidad básica post-deploy | Detectar problemas críticos rápido | Cada deploy | Producción | Health checks, login, operación básica | Scripts custom, Postman |
| Fuzz Testing | Inputs aleatorios/malformados | Encuentra crashes, vulnerabilidades | Parsers, APIs públicas | Input validation | Generar inputs inválidos masivamente | AFL, libFuzzer |
1.5 📏 Métricas de Testing
| Métrica | Fórmula | Meta | Herramienta |
|---|---|---|---|
| Code Coverage | (Líneas ejecutadas / Total líneas) × 100 | ≥80% lógica crítica, ≥60% general | JaCoCo, Coverage.py |
| Test Success Rate | (Tests pasados / Total tests) × 100 | 100% en main branch | CI/CD dashboard |
| Test Execution Time | Tiempo suite completa | <5 min unitarios, <15 min E2E | CI logs |
| Defect Escape Rate | Bugs en prod / Total bugs encontrados | <5% | Jira, GitHub Issues |
| Mutation Score | (Mutantes muertos / Total mutantes) × 100 | ≥70% | Stryker, mutmut |
1.6 🎯 Estrategia de Testing por Proyecto
| Tipo Proyecto | Enfoque Testing | Razón |
|---|---|---|
| Startup/MVP | E2E en flujos críticos + unitarios en lógica compleja | Velocidad, máximo valor/esfuerzo |
| Producto maduro | Pirámide completa 10 | Estabilidad, refactoring seguro |
| Sistema legacy | Tests de regresión (E2E) + caracterización | Proteger funcionalidad existente |
| Microservicios | Contract testing + integración | Evitar breaking changes entre equipos |
| Biblioteca/SDK | 100% cobertura unitaria + PBT | Usado por terceros, máxima confianza |
1.7 🚫 Anti-patrones
| Anti-patrón | Problema | Solución |
|---|---|---|
| Tests frágiles | Fallan por cambios no relacionados (IDs, orden) | Usar selectores semánticos, no acoplar a estructura |
| Timeouts arbitrarios | sleep(5) en E2E |
Usar wait explícitos (waitForSelector) |
| Tests interdependientes | Test B depende que A corra primero | Tests aislados, setup/teardown por test |
| Assertions múltiples | Un test valida 10 cosas | Un concepto por test, nombres claros |
| Mocks excesivos | Mockear todo, no testear nada real | Mockear solo lo externo/lento |