1. Skip to content

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

1.8 📚 Recursos