Pruebas en JavaScript: Unit, Integration, E2E a nivel avanzado

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: Por qué las pruebas avanzadas son un must-have para un proyecto JavaScript

En el desarrollo moderno con Node.js, las pruebas han dejado de ser una etapa opcional. Sin una cobertura de código de calidad con pruebas, cualquier refactorización o adición de nueva funcionalidad corre el riesgo de convertirse en una "ruleta rusa". Sin embargo, simplemente escribir algunos assert no es suficiente. A nivel avanzado, el desarrollador debe dominar tres capas principales: Pruebas Unitarias (verificación de módulos aislados), Pruebas de Integración (interacción de componentes, BD, API) y Pruebas E2E (simulación de acciones del usuario). En este artículo, analizaremos técnicas prácticas para cada capa usando Node.js con herramientas modernas: Jest, Supertest y Playwright.



1. Pruebas Unitarias: aislamiento, mocks y stubs a nivel avanzado

Las pruebas unitarias verifican el funcionamiento de una función o módulo de forma aislada de las dependencias externas (BD, sistema de archivos, solicitudes de red). La tarea clave es simular correctamente estas dependencias para que la prueba sea rápida y determinista.



Técnicas avanzadas de mocking en Jest

Consideremos un ejemplo: una función que accede a una API externa y almacena en caché el resultado en Redis. Necesitamos probar la lógica de caché sin realizar solicitudes reales.

// cacheService.jsconst axios = require('axios');const redis = require('redis');

class CacheService { constructor() { this.client = redis.createClient(); }

async fetchData(url) { const cached = await this.client.get(url); if (cached) return JSON.parse(cached);

const response = await axios.get(url); await this.client.setEx(url, 3600, JSON.stringify(response.data)); return response.data; }}

module.exports = CacheService;


// cacheService.test.jsconst CacheService = require('./cacheService');const axios = require('axios');const redis = require('redis');

jest.mock('axios');jest.mock('redis', () => ({ createClient: jest.fn(() => ({ get: jest.fn(), setEx: jest.fn() }))}));

describe('CacheService', () => { let service; let mockRedisClient;

beforeEach(() => { mockRedisClient = redis.createClient(); service = new CacheService(); });

test('should return cached data if present', async () => { const url = 'https://api.example.com/data'; const cachedData = { id: 1, value: 'cached' }; mockRedisClient.get.mockResolvedValue(JSON.stringify(cachedData));

const result = await service.fetchData(url);

expect(result).toEqual(cachedData); expect(axios.get).not.toHaveBeenCalled(); });

test('should fetch and cache data if not cached', async () => { const url = 'https://api.example.com/data'; const apiData = { id: 2, value: 'fresh' }; mockRedisClient.get.mockResolvedValue(null); axios.get.mockResolvedValue({ data: apiData });

const result = await service.fetchData(url);

expect(result).toEqual(apiData); expect(mockRedisClient.setEx).toHaveBeenCalledWith(url, 3600, JSON.stringify(apiData)); });});

Puntos clave:

  • jest.mock('axios') simula automáticamente todo el módulo axios.
  • Para Redis usamos una fábrica que devuelve un mock con los métodos get y setEx.
  • Verificamos que cuando hay caché, la llamada externa no ocurre.


2. Pruebas de Integración: probando la interacción con una BD real y API

Las pruebas de integración verifican cómo diferentes partes del sistema funcionan juntas. Para Node.js, esto a menudo implica probar rutas de Express con una base de datos real (o de prueba). La mejor herramienta es Supertest en combinación con Jest.



Configuración de una BD de prueba y Supertest

Ejemplo: API para gestionar usuarios. Usamos SQLite en memoria para aislamiento

Blogs

Book Recommendations