Cómo mockear dependencias con Jest

Cuando queremos probar nuestro código, muchas veces nos encontramos con dependencias internas que no queremos invocar en los tests. Si ejecutamos esas dependencias reales, no podemos tener la certeza de si lo que falla es nuestra propia lógica o un servicio externo fuera de nuestro control.
Hoy vamos a agregar pruebas a una aplicación de clima de ejemplo usando Jest y mockeando sus dependencias.
👉🏽 Aquí puedes leer otros artículos sobre Frontend y Angular en español
La aplicación
Nuestra aplicación de ejemplo tiene dos archivos principales: weatherAPI.js y showWeather.js. El módulo showWeather utiliza el código de weatherAPI.js para mostrar la información del clima.
El archivo weatherAPI.js:
const getWeather = (format) => {
const min = format = 'C' ? 50 : 100;
return 50;
}
module.exports = { getWeather}El archivo showWeather.js:
const weatherAPI = require('./weatherAPI');
const messageWeather = () => {
let weather = weatherAPI.getWeather('C');
return `Today weather is ${weather}, have a nice day!`
}
module.exports = { messageWeather }Ahora que tenemos clara la estructura de la aplicación, el siguiente paso es escribir las pruebas para el código de showWeather.
Puedes ver el código final de ejemplo en el repositorio de GitHub: https://github.com/danywalls/02-mocking-code
Escribiendo la prueba
Usamos la función test de Jest para declarar nuestra prueba, junto con expect y el comparador toBe para las aserciones.
El objetivo principal aquí es el mockeo. Si quieres leer más sobre las funciones de aserción, puedes consultar la documentación oficial de Jest.
const weatherAPI = require('./weatherAPI');
const { messageWeather } = require('./showWeather');
test('should return weather message with celsius temperature', () => {
const result = messageWeather();
const expected = `Today weather is 50, have a nice day!`;
expect(result).toBe(expected);
})Podemos ejecutar nuestra prueba con npx jest y funciona a la primera:
PASS ./showWeather.test.js
✓ Return the Weather with C (2 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.376 s, estimated 1 sEsto se ve bien, pero hay un detalle importante: nuestra prueba llama a getWeather ejecutando el código real, cuando en realidad mi prueba solo necesita cubrir el código de showWeather.
¿Cómo simular los métodos de weatherAPI?
Jest nos ofrece varias formas de mockear los métodos de weatherAPI:
- Sobrescribir los métodos con jest.fn.
- Usar jest.spyOn.
- Mockear el módulo completo con jest.mock.
Podemos usar cualquiera de estas tres opciones para obtener el mismo resultado, así que puedes elegir la que mejor se adapte a tu proyecto.
Sobrescribir funciones con jest.fn
La forma más directa es reasignar el método getWeather con una función simulada usando jest.fn. Actualizamos la prueba siguiendo estos tres pasos:
- Asignamos
jest.fndevolviendo20por defecto. - Validamos que el método
getWeatherreciba el parámetro'C'. - Comprobamos que el resultado obtenido sea igual al valor esperado.
test('should return weather message with celsius temperature', () => {
weatherAPI.getWeather = jest.fn((format) => `20`);
expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
const result = messageWeather();
const expected = `Today weather is 20, have a nice day!`;
expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
expect(result).toBe(expected);
weatherAPI.getWeather.mockRestore();
})La función
mockRestoresirve para restaurar el valor original de la funcióngetWeather.
Usar jest.spyOn
jest.spyOn nos ayuda a asignar una función simulada a un método existente en un objeto, en este caso el objeto weatherAPI.
Con spyOn interceptamos la función y usamos mockImplementation para devolver el valor simulado:
jest.spyOn(weatherAPI, 'getWeather')
weatherAPI.getWeather.mockImplementation((format) => `20`)
const result = messageWeather();
const expected = `Today weather is 20, have a nice day!`;
expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
expect(result).toBe(expected);
weatherAPI.getWeather.mockRestore();Mockear el módulo completo
En lugar de mockear cada función por separado, Jest nos permite simular el módulo completo utilizando jest.mock.
Creamos el directorio __mocks__ en la misma ruta del archivo que queremos simular. Dentro creamos un archivo con el mismo nombre del módulo, en este caso weatherAPI.js, y exportamos las funciones simuladas:
module.exports = {
getWeather: jest.fn((format) => `20`)
}En nuestra prueba, le indicamos a Jest que use el módulo simulado mediante jest.mock:
jest.mock('./weatherAPI');
test('should return weather message with celsius temperature', () => {
const result = messageWeather();
const expected = `Today weather is 20, have a nice day!`;
expect(weatherAPI.getWeather).toHaveBeenCalledWith('C');
expect(result).toBe(expected);
weatherAPI.getWeather.mockRestore();
})Probar funciones asíncronas
Las funciones asíncronas son muy habituales en nuestro código. Vamos a agregar una nueva función con promesas en weatherAPI y a utilizarla en showWeather.js.
Puedes leer más sobre las palabras clave async y await en MDN.
const getMetaWeather = async () => {
return new Promise((resolve) => {
resolve('Summer time!')
})
}
module.exports = { getWeather, getMetaWeather}La función getMetaWeather retorna una promesa. Para consumirla en nuestra nueva función showWeatherStatus, usamos async y await para esperar su respuesta:
const showWeatherStatus = async () => {
let weather = await weatherAPI.getMetaWeather();
return `${weather}, Enjoy!`
}
module.exports = { messageWeather, showWeatherStatus }El siguiente paso es actualizar nuestras pruebas para cubrir showWeatherStatus. Editamos el archivo __mocks__/weatherAPI.js para que la versión simulada de getMetaWeather retorne una promesa con los datos del mock:
getMetaWeather: jest.fn(() => new Promise((resolve) => resolve('Great day') ))Ahora creamos una nueva prueba para el estado asíncrono del clima usando async y await. Como actualizamos los mocks, nuestra prueba tomará automáticamente la implementación simulada:
test('Should return async weather status', async () => {
const result = await showWeatherStatus();
const expected = 'Great day, Enjoy!';
expect(result).toBe(expected);
})En todos los casos, nuestras pruebas pasan correctamente:
PASS ./showWeather.test.js
Show Weather functions
✓ should return weather message with celsius temperature (3 ms)
✓ Should return async weather (1 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.383 s, estimated 1 sConclusión
Jest hace que sea muy sencillo probar nuestro código y aislar dependencias externas. Personalmente te recomiendo usar el directorio __mocks__ para sobrescribir módulos completos, ya que facilita actualizar los mocks y hace que los archivos de prueba sean más fáciles de leer al contener únicamente los métodos de aserción.
Si quieres conocer más opciones sobre cómo hacer mocks con Jest, puedes consultar la documentación oficial.
Modern frontend development — Angular, React, TypeScript, accessibility, and performance.
Artículos Relacionados
Compartir este artículo
Si esta guía te resultó útil, compártela con tu equipo o con otros desarrolladores.
Software real. Lecciones reales.
Comparto las lecciones que aprendí por las malas, para que puedas evitarlas o estar preparado cuando ocurran.
Únete a 13,800+ desarrolladores y lectores.
Cero spam. Cancela tu suscripción en cualquier momento.