Mocking sin volverse loco: cuándo usarlo y cuándo parar
⏱ Tiempo de lectura estimado: 7 minutos
Hay un momento en la vida de cualquier dev en el que abres un test que escribiste hace tres meses y no entiendes absolutamente nada. No el código de producción — el test. Ves doce mocks encadenados, un spy sobre un spy, y te preguntas: ¿esto realmente está probando algo, o solo está probando que yo sé configurar Jest?
Esa sensación es la señal. Tu suite de tests tiene un problema de mocking.
No es que el mocking sea malo. Es que es adictivo. Una vez que descubres que puedes aislar cualquier dependencia con tres líneas de código, empiezas a mockear todo lo que se mueve. Base de datos, HTTP, el reloj del sistema, hasta el Math.random. Y de repente tienes cien tests que pasan en verde pero tu aplicación falla en producción. Bienvenido al club.
Qué significa realmente mockear (más allá de la definición de manual)
Un mock no es simplemente "reemplazar algo real por algo falso". Es una decisión de diseño. Cuando mockeas una dependencia, estás diciendo: "confío en que esta parte funciona, y quiero probar solo mi lógica". Eso tiene sentido. El problema es cuando empiezas a mockear cosas que son exactamente tu lógica.
En mi experiencia, el error más común no es mockear demasiado en abstracto — es mockear en el lugar equivocado. Por ejemplo, tienes un servicio que transforma datos y llama a un repositorio. Si en el test de ese servicio mockeas el repositorio, bien. Pero si además mockeas la función de transformación que es justamente lo que quieres probar... acabas de escribir un test que solo verifica que tus mocks se llaman en orden. Eso no es testing, es teatro.
Los tres tipos de dobles de prueba que confundimos todo el tiempo
Aquí va algo que no siempre se explica bien: mock, stub y spy no son lo mismo, aunque los frameworks los mezclen.
Un stub devuelve datos predefinidos. Lo usas cuando necesitas que algo responda de una forma específica para que tu código tome cierto camino. No te importa si fue llamado o cuántas veces.
Un mock sí verifica comportamiento. Espera ser llamado de cierta manera y falla el test si no lo fue. Úsalo cuando el cómo se llama algo es parte de lo que quieres probar.
Un spy observa sin reemplazar completamente. Deja que el código real corra, pero registra qué pasó. Útil cuando quieres verificar efectos secundarios sin romper el flujo original.
El punto es que usar jest.mock() para todo es como usar un martillo para atornillar. Funciona a veces, pero no es la herramienta correcta.
Cuándo el mocking tiene sentido de verdad
Hay situaciones donde mockear es la decisión correcta y no deberías dudar:
Dependencias externas que no controlas. Llamadas a APIs de terceros, servicios de email, pasarelas de pago. No quieres que tu test falle porque la API de Stripe tuvo un hiccup a las 3am. Ahí el mock es tu amigo.
Operaciones lentas o costosas. Si tu test necesita escribir en una base de datos real, esperar una cola de mensajes o procesar un archivo de 500MB, el tiempo de ejecución se vuelve insostenible. Mockear tiene sentido para mantener los tests rápidos y ejecutables en CI sin infraestructura pesada.
Efectos secundarios que no puedes revertir fácilmente. Enviar un SMS real en cada test run no es viable. Mockear el servicio de notificaciones tiene toda la lógica del mundo.
Ahora bien, ojo que hay una trampa aquí. Cuando mockeas una dependencia externa, estás asumiendo que tu mock se comporta igual que la cosa real. Si la API cambia su contrato y tu mock no lo refleja, tus tests siguen en verde pero tu app está rota. Por eso los mocks deben ir acompañados de tests de integración o contract testing. No son sustitutos — son complementos.
La señal de que estás mockeando demasiado
Si tienes que modificar tres mocks cada vez que cambias una línea de lógica de negocio, algo está mal. No con los mocks — con el diseño. Tests que se rompen por cada refactor menor no son tests útiles, son lastre.
Otro síntoma: si lees el test y no puedes entender qué comportamiento está verificando sin leer también todo el setup de mocks, ese test está documentando implementación, no comportamiento. Y la implementación cambia. El comportamiento debería ser más estable.
En mi experiencia, cuando llego a ese punto prefiero preguntarme: ¿puedo hacer este código más testeable sin mockear tanto? Muchas veces la respuesta es inyectar dependencias de forma explícita, extraer funciones puras, o simplificar la arquitectura. El mocking excesivo a veces es un síntoma de acoplamiento que no habíamos visto.
Una regla práctica para decidir si mockear o no
Antes de mockear algo, hazte esta pregunta: ¿estoy mockeando porque es necesario para aislar mi lógica, o porque es conveniente para evitar configurar algo?
Si la respuesta es la segunda, considera si vale la pena configurar ese algo. Una base de datos SQLite en memoria para tests de integración no es tan difícil de montar y te da muchísima más confianza que un mock del repositorio. Herramientas como Testcontainers hacen que levantar una Postgres real para tests sea cosa de pocas líneas.
Discho esto, no estoy diciendo que nunca uses mocks. Estoy diciendo que cada mock es una deuda de confianza. Cada vez que mockeas algo, estás apostando a que tu simulación es fiel a la realidad. Esa apuesta puede ser muy razonable o puede ser una bomba de tiempo.
Usa mocks con intención. Documenta por qué estás mockeando esa dependencia específica. Y revisa periódicamente si esos mocks siguen siendo válidos.
Antes de irte
Si sientes que tu suite de tests es un laberinto de mocks que nadie quiere tocar, no eres el único. Eso le pasa a equipos con años de experiencia, no solo a los que están empezando. Nadie escribe la estrategia de mocking perfecta al primer intento — se aprende rompiéndola.
Empieza por el siguiente test que tengas que escribir: pregúntate si realmente necesitas ese mock antes de añadirlo. Esa pausa de tres segundos puede ahorrarte horas de debugging después.
Enlazado interno sugerido:
Alt text sugerido para imagen destacada: "Diagrama mostrando la diferencia entre mock, stub y spy en un test unitario con ejemplos de código"
💬 Comentarios