Contenido del curso

Mocks y stubs en pruebas de integración

Resumen

Las pruebas de integración verifican que tu capa de aplicación funcione correctamente cuando depende de bases de datos, APIs externas o servicios de terceros. Si trabajas con arquitecturas limpias y necesitas validar tu dominio sin sacrificar velocidad ni control, los dobles de prueba como mocks y stubs se vuelven tus mejores aliados.

Aquí te explico cómo funcionan, qué problemas resuelven y cómo implementarlos con un framework como Mockito en un caso real.

¿Qué es una prueba de integración y en qué se diferencia de una unitaria?

Una prueba de integración valida que tu sistema funcione correctamente junto con sus dependencias. A diferencia de una prueba unitaria, aquí entran en juego dos componentes que debes diferenciar desde el inicio.

El primero es el sistema bajo prueba (SUT), que en una arquitectura limpia suele ser tu dominio. El segundo es el componente del cual se depende (CD): una base de datos, un CRM, una API de terceros o cualquier servicio externo que tu sistema necesite para cumplir su tarea.

¿Cuándo uso una prueba de integración en lugar de una unitaria? Cuando tu sistema bajo prueba tiene dependencias externas que afectan su comportamiento, como repositorios, servicios de mensajería o APIs. Si no hay dependencias, una prueba unitaria es suficiente.

¿Por qué probar con dependencias reales es tan complicado?

Probar contra componentes reales suena ideal, pero en la práctica trae limitaciones que vale la pena conocer antes de escribir tu primera prueba [2:10].

  • Acceso lento: si tu base de datos vive en un servidor en Europa o Estados Unidos, cada prueba tarda más de lo razonable.
  • Control del resultado: como no controlas el componente externo, predecir su respuesta exacta se vuelve difícil y suele requerir inicializaciones previas.
  • Efectos colaterales: imagina probar el envío de correos y que cada ejecución dispare emails reales a usuarios reales.
  • Disponibilidad limitada: hay sistemas que solo existen en producción, lo que bloquea pruebas locales.
  • Costos económicos: muchas APIs cobran por llamado, así que cientos de pruebas automatizadas pueden inflar tu factura mensual.

Estas dificultades son justo el motivo por el que existen los dobles de prueba.

¿Qué son los dobles de prueba y para qué sirven?

Un doble de prueba es un objeto que pones en lugar del objeto real con el único propósito de poder ejecutar la prueba [4:30]. Es como un sustituto que tú mismo construyes, lo que te permite controlar resultados, evitar accesos lentos y eliminar efectos colaterales.

¿Qué diferencia hay entre un mock y un stub? Un stub devuelve respuestas predefinidas cuando se le llama. Un mock hace lo mismo, pero además registra cómo fue invocado para que puedas verificar interacciones, como cuántas veces se llamó o con qué parámetros.

La pregunta lógica aparece rápido: si reemplazas el objeto real, ¿cómo sabes que el real funciona? La respuesta está en combinar estrategias. Mantienes algunas pruebas con componentes reales y subes en la pirámide de pruebas hacia las pruebas extremo a extremo, donde sí usas todo real. Eso sí, estas últimas son pocas porque resultan lentas, costosas y difíciles de implementar.

¿Cómo implementar mocks con Mockito en una prueba real?

Una prueba de integración aplicada a un flight service muestra muy bien el flujo. El framework usado aquí es Mockito, ampliamente adoptado en el ecosistema Java para crear mocks [7:15].

Podrías hacer mocks sin framework, pero a medida que tus pruebas crecen en complejidad, una herramienta dedicada te ahorra muchísimo trabajo.

¿Cómo se crean y configuran los mocks?

El flujo típico tiene tres momentos clave:

  1. Crear los mocks de los repositorios que usa el servicio. Le dices al framework: existe esta interfaz, genera un objeto que la implemente.
  2. Inicializar los datos que quieres que el mock devuelva. Aquí controlas el resultado esperado para validar tu sistema bajo prueba.
  3. Definir el comportamiento: por ejemplo, indicar que cuando se llame al repositorio buscando una ruta, devuelva un resultado específico.

Después ejecutas el código de tu servicio y verificas el resultado. En el ejemplo, la prueba confirma que se devolvieron exactamente dos vuelos, los mismos que se configuraron al inicio.

¿Qué validaciones avanzadas puedo hacer con un mock?

Aquí es donde los mocks brillan frente a los stubs simples. Puedes verificar:

  • Que el repositorio haya sido llamado exactamente una vez.
  • Que se haya invocado con los parámetros esperados.
  • Que ciertas interacciones entre tu servicio y sus dependencias ocurran en el orden correcto.

Eso te da una interacción muy fuerte con el servicio sin depender de la base de datos. Es la verdadera ventaja de las pruebas de integración con dobles.

Conceptos y términos clave que aparecen en la clase

Para aterrizar lo aprendido, vale la pena fijar estos términos:

  • Sistema bajo prueba (SUT): el componente que estás verificando, normalmente tu dominio [1:20].
  • Componente del cual se depende (CD): la dependencia externa que tu SUT necesita [1:35].
  • Doble de prueba: objeto sustituto que reemplaza al real durante la prueba [4:30].
  • Mock: doble configurable que registra interacciones y permite validar llamadas [5:50].
  • Stub: doble que solo devuelve respuestas predefinidas [5:50].
  • Mockito: framework de mocks ampliamente usado en Java [7:15].
  • Pirámide de pruebas: modelo que organiza pruebas unitarias, de integración y extremo a extremo según costo y velocidad [5:00].

Dominar estos conceptos te permite probar arquitecturas limpias sin que la infraestructura te frene. Si quieres profundizar, la ruta de aprendizaje de QA y automatización de pruebas es el siguiente paso natural.

¿Has usado mocks o stubs en tus proyectos? Cuéntame en los comentarios qué framework prefieres y qué retos has encontrado al probar tu capa de aplicación.