Guía avanzada de Jest con mocks y spies
- javascript
- react
- Testing
- Unit test
- Mocking
- jest.fn
- jest.spyOn
- jest.mock
- Asynchronous testing
- MSW Mocks service worker
🧠 Conceptos clave
- En Jest, mocks y spies permiten aislar dependencias externas y observar cómo se comporta el código bajo prueba.
- Un mock reemplaza una función, módulo o clase para simular su comportamiento.
- Un spy rastrea llamadas y argumentos de una función real sin reemplazarla por completo.
- Son esenciales en pruebas unitarias y de integración para evitar efectos secundarios (como peticiones HTTP, acceso a DB, o temporizadores).
- Se pueden aplicar a funciones, módulos completos o librerías externas (como
axiosofetch).
🧩 Tipos de mocks
- Funciones simuladas
Se crean conjest.fn()y pueden registrar llamadas o devolver valores personalizados.
const mockCallback = jest.fn(x => x * 2)
[1, 2, 3].forEach(mockCallback)
expect(mockCallback).toHaveBeenCalledTimes(3)
expect(mockCallback).toHaveBeenCalledWith(2)
- Espías (spies)
Usanjest.spyOn(obj, 'método')para observar llamadas sin reemplazar el método original.
javascript
const user = { save: () => 'ok' }
const spy = jest.spyOn(user, 'save')
user.save()
expect(spy).toHaveBeenCalled()
spy.mockRestore()
- Mocks de módulos completos
Simulan dependencias completas como librerías o servicios HTTP.
javascript
jest.mock('axios')
import axios from 'axios'
axios.get.mockResolvedValue({ data: { message: 'ok' } })
⚙️ Mocking de dependencias externas
- Ideal cuando una función depende de servicios externos o módulos de terceros.
- Ejemplo con
fetchy MSW Mocks service worker:
javascript
global.fetch = jest.fn(() =>
Promise.resolve({ json: () => Promise.resolve({ id: 1, name: 'Eduardo' }) })
)
import { getUser } from '../api'
test('obtiene datos de usuario', async () => {
const user = await getUser(1)
expect(user.name).toBe('Eduardo')
expect(fetch).toHaveBeenCalledWith('/users/1')
})
- Para entornos más realistas (sin sobrescribir
fetchglobal), usa MSW Mocks service worker para interceptar peticiones en test suites o E2E.
🧱 Mocks parciales y restauración
jest.requireActual()permite usar partes reales de un módulo mockeado.mockRestore()yclearAllMocks()evitan contaminación entre tests.
javascript
const utils = { sumar: (a, b) => a + b }
jest.spyOn(utils, 'sumar').mockImplementation(() => 42)
test('usa mock temporal', () => {
expect(utils.sumar(2, 2)).toBe(42)
})
afterEach(() => {
jest.restoreAllMocks()
})
🔄 Mocks en react y componentes
- Para componentes que usan hooks o contextos:
javascript
import { render, screen } from '@testing-library/react'
import * as hooks from '../useAuth'
import Dashboard from '../Dashboard'
jest.spyOn(hooks, 'useAuth').mockReturnValue({ user: { name: 'Edu' } })
test('muestra el nombre del usuario', () => {
render(<Dashboard />)
expect(screen.getByText(/Edu/)).toBeInTheDocument()
})
- Este enfoque es útil cuando el hook o contexto obtiene datos externos, como autenticación o configuración remota.
📊 Casos avanzados de uso
- Timers simulados
javascript
jest.useFakeTimers()
const timer = jest.fn()
setTimeout(timer, 1000)
jest.advanceTimersByTime(1000)
expect(timer).toHaveBeenCalled()
- Mocks dinámicos por test
javascript
beforeEach(() => {
jest.resetModules()
})
- Reemplazo temporal de dependencias para probar rutas o comportamientos alternos.
💡 Buenas prácticas
- Mantén los mocks locales a cada test siempre que sea posible.
- Usa
jest.clearAllMocks()enafterEach()para evitar contaminación. - Prefiere
jest.spyOn()ajest.fn()cuando quieras conservar la funcionalidad original. - Documenta qué dependencias se mockean y por qué.
- Evita mocks innecesarios en tests de integración: usa datos reales o entornos simulados.
🔍 Recursos recomendados
- Documentación oficial de Mocks en Jest
- Guía de mocks automáticos y manuales
- MSW Mocks service worker para simular APIs REST/GraphQL.
- Testing Library para testear componentes React que dependen de hooks o APIs.
¿Te gusta este contenido? Suscríbete vía RSS