Back

Pruebas Unitarias vs Pruebas de Integración en JavaScript: Cuándo Usar Cada Una

Pruebas Unitarias vs Pruebas de Integración en JavaScript: Cuándo Usar Cada Una

Todo desarrollador de JavaScript enfrenta la misma pregunta al construir aplicaciones confiables: ¿debería escribir más pruebas unitarias o pruebas de integración? Si eliges mal, pasarás horas depurando pruebas frágiles o enviarás bugs a producción. La respuesta no se trata de elegir una sobre la otra, sino de entender cuándo cada tipo ofrece el mayor valor.

Este artículo aclara las diferencias entre las pruebas unitarias y de integración en JavaScript, te muestra ejemplos prácticos de cada una y proporciona un marco de decisión para equilibrar ambas en tu estrategia de testing.

Puntos Clave

  • Las pruebas unitarias verifican piezas de código aisladas para obtener velocidad y precisión
  • Las pruebas de integración validan las interacciones entre componentes para obtener confianza en escenarios reales
  • Una distribución 70-20-10 (unitarias-integración-E2E) funciona para la mayoría de proyectos JavaScript
  • Elige según lo que estés probando: los algoritmos necesitan pruebas unitarias, los flujos de trabajo necesitan pruebas de integración

¿Qué Son las Pruebas Unitarias?

Las pruebas unitarias verifican que piezas individuales de código funcionen correctamente de forma aislada. Piensa en ello como probar un solo bloque de LEGO antes de añadirlo a tu estructura.

En JavaScript, una prueba unitaria típicamente se enfoca en:

  • Una única función o método
  • Un componente sin sus hijos
  • Una clase o módulo específico

Ejemplo de Prueba Unitaria

// calculator.js
export function calculateDiscount(price, percentage) {
  if (percentage < 0 || percentage > 100) {
    throw new Error('Invalid percentage');
  }
  return price * (1 - percentage / 100);
}

// calculator.test.js
import { calculateDiscount } from './calculator';

test('applies 20% discount correctly', () => {
  expect(calculateDiscount(100, 20)).toBe(80);
});

test('throws error for invalid percentage', () => {
  expect(() => calculateDiscount(100, 150)).toThrow('Invalid percentage');
});

Las pruebas unitarias destacan en:

  • Velocidad: Milisegundos por prueba ya que no hay operaciones de I/O ni dependencias externas
  • Precisión: Identifican ubicaciones exactas de fallos
  • Estabilidad: Rara vez se rompen debido a cambios no relacionados

¿Qué Son las Pruebas de Integración?

Las pruebas de integración verifican que múltiples partes de tu aplicación funcionen correctamente juntas. En lugar de probar el bloque de LEGO solo, estás probando cómo varios bloques se conectan.

Las pruebas de integración en JavaScript típicamente cubren:

  • Interacciones de componentes con APIs
  • Múltiples módulos trabajando juntos
  • Operaciones de base de datos con lógica de negocio
  • Componentes de UI con gestión de estado

Ejemplo de Prueba de Integración

// userProfile.test.js
import { render, screen, waitFor } from '@testing-library/react';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import UserProfile from './UserProfile';

const server = setupServer(
  rest.get('/api/user/:id', (req, res, ctx) => {
    return res(ctx.json({ 
      id: req.params.id, 
      name: 'Jane Doe',
      role: 'Developer' 
    }));
  })
);

beforeAll(() => server.listen());
afterAll(() => server.close());

test('displays user data after loading', async () => {
  render(<UserProfile userId="123" />);
  
  expect(screen.getByText(/loading/i)).toBeInTheDocument();
  
  await waitFor(() => {
    expect(screen.getByText('Jane Doe')).toBeInTheDocument();
    expect(screen.getByText('Developer')).toBeInTheDocument();
  });
});

Las pruebas de integración proporcionan:

  • Confianza: Validan flujos de trabajo reales de usuarios
  • Cobertura: Prueban la interacción entre componentes
  • Realidad: Detectan problemas que las pruebas unitarias pasan por alto

Diferencias Clave que Importan

Alcance y Aislamiento

Las pruebas unitarias aíslan el código usando mocks y stubs. Controlas cada variable. Las pruebas de integración usan implementaciones reales donde sea posible, simulando solo los límites externos como APIs o bases de datos.

Velocidad de Ejecución

Las pruebas unitarias se ejecutan en 1-50ms cada una. Puedes ejecutar miles en segundos. Las pruebas de integración toman 100-500ms o más. Involucran configuración, limpieza y a veces operaciones de I/O reales.

Costo de Mantenimiento

Las pruebas unitarias se rompen solo cuando cambia su unidad específica. Las pruebas de integración pueden romperse por cambios en cualquier parte del flujo probado, requiriendo más tiempo de investigación.

Detección de Bugs

Las pruebas unitarias detectan errores de lógica y casos extremos en código aislado. Las pruebas de integración detectan problemas de conexión, suposiciones incorrectas y violaciones de contratos entre componentes.

Cuándo Usar Cada Tipo

Escribe Pruebas Unitarias Para:

  • Funciones puras: Lógica de negocio, cálculos, transformaciones de datos
  • Algoritmos complejos: Ordenamiento, búsqueda, reglas de validación
  • Casos extremos: Manejo de errores, condiciones límite
  • Funciones de utilidad: Formateadores, parseadores, helpers

Escribe Pruebas de Integración Para:

  • Interacciones con APIs: Peticiones HTTP, manejo de respuestas
  • Flujos de trabajo de usuario: Procesos de múltiples pasos, envío de formularios
  • Integración de componentes: Comunicación entre componentes padre-hijo
  • Gestión de estado: Acciones de Redux, flujos de Context API
  • Operaciones de base de datos: Operaciones CRUD con lógica de negocio

La Estrategia Práctica de Testing

La mayoría de proyectos JavaScript exitosos siguen una distribución 70-20-10:

  • 70% Pruebas unitarias: Retroalimentación rápida, depuración fácil
  • 20% Pruebas de integración: Confianza en las interacciones entre componentes
  • 10% Pruebas end-to-end: Validación final de rutas críticas

Esta no es una regla rígida—ajusta según el tipo de aplicación. Las aplicaciones con muchas APIs necesitan más pruebas de integración. Las librerías con muchos algoritmos necesitan más pruebas unitarias.

Integración en el Pipeline CI/CD

Estructura tu pipeline para obtener retroalimentación rápida:

  1. Pre-commit: Ejecuta pruebas unitarias (< 5 segundos)
  2. Pull request: Ejecuta todas las pruebas unitarias y de integración
  3. Pre-deploy: Ejecuta la suite completa de pruebas incluyendo las E2E

Herramientas como Jest para pruebas unitarias, Testing Library para pruebas de integración, y MSW para simulación de APIs hacen que este pipeline sea eficiente y mantenible.

Errores Comunes a Evitar

  1. Exceso de mocking en pruebas de integración: Anula el propósito de probar interacciones
  2. Probar detalles de implementación: Enfócate en el comportamiento, no en la estructura interna
  3. Ignorar la velocidad de las pruebas: Las pruebas lentas desalientan su ejecución frecuente
  4. Escribir pruebas después de los bugs: El testing proactivo previene problemas

Conclusión

Las pruebas unitarias y de integración en JavaScript no son estrategias competidoras—son herramientas complementarias. Las pruebas unitarias te dan velocidad y precisión para lógica aislada. Las pruebas de integración proporcionan confianza de que tus componentes funcionan correctamente juntos.

Comienza con pruebas unitarias para lógica de negocio y funciones puras. Añade pruebas de integración para rutas críticas de usuario e interacciones entre componentes. Evita los debates religiosos sobre filosofías de testing y enfócate en lo que te da confianza para enviar código.

La mejor estrategia de testing en JavaScript es la que detecta bugs antes de que lo hagan los usuarios mientras mantiene alta tu velocidad de desarrollo. Equilibra ambos tipos según las necesidades de tu aplicación y ajusta a medida que aprendes qué se rompe con más frecuencia.

Preguntas Frecuentes

Siempre simula las dependencias externas en pruebas unitarias. Esto incluye bases de datos, APIs, sistemas de archivos y otros servicios. El mocking asegura que las pruebas se ejecuten rápido, permanezcan predecibles y realmente prueben tu código de forma aislada en lugar del comportamiento de sistemas externos.

Comienza preguntándote qué podría romperse. Si la lógica en sí es compleja, escribe pruebas unitarias primero. Si la funcionalidad involucra múltiples componentes comunicándose entre sí o servicios externos, prioriza las pruebas de integración. La mayoría de funcionalidades se benefician de ambos tipos.

Las pruebas unitarias deberían completarse en menos de 10 segundos para la suite completa. Las pruebas de integración pueden tomar 1-5 minutos. Si tus pruebas tardan más, divídelas en trabajos paralelos o identifica pruebas lentas que necesiten optimización. Las pruebas rápidas alientan a los desarrolladores a ejecutarlas con frecuencia.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay