Mockear o No Mockear

Mockear es útil, pero “qué mockear” suele resultar más complicado de lo esperado si no tratas esto con cuidado.
Cómo escapar del infierno del mocking
¿Qué pasa realmente cuando creamos un mock? ¿Qué tipos hay? ¿Es bueno o malo mockear? Como siempre, depende del contexto. Aquí veremos las situaciones principales: cuándo mockear, cuándo no hacerlo, y sobre todo por qué.
¿Qué pasa cuando mockeas algo?
Primero, deberíamos definir qué es un mock:
En un test unitario, los objetos mock pueden simular el comportamiento de objetos reales complejos y por lo tanto son útiles cuando es impracticable o imposible incorporar un objeto real en un test unitario.
Mockear tiene sentido en testing unitario. Un test de integración pasa por la implementación real, verificando cómo interactúan varias unidades. Estos tests sí pueden hablar con la BD o el sistema de archivos. Partimos de esta base: un test unitario es rápido, determinista, no depende de recursos externos y no requiere contexto especial para ejecutarse.
Los mocks cumplen el contrato de la interfaz. Nos permiten testear funcionalidad sin invocar clases colaboradoras complejas.
Un mock es un doble de test que sustituye la implementación real. Además, puede verificar cómo el código bajo test lo utilizó durante la ejecución.
Recomiendo encarecidamente que leas este post si quieres entrar en los detalles de por qué Mockear es un code smell (Temas como estos: ¿Qué es un mock? ¿Qué es un test unitario? ¿Qué es la cobertura de tests? ¿Qué es el acoplamiento fuerte? ¿Qué causa el acoplamiento fuerte? ¿Qué tiene que ver la composición con el mocking? ¿Cómo eliminamos el acoplamiento? ¡y más!)
El problema con mockear
Cuando mockeas, anulas la lógica de la clase mockeada. La lógica real queda oculta, y ahí es donde los bugs se esconden. Ten en cuenta que:
-
El mock puede tener atributos, métodos o argumentos que el objeto real no tiene.
-
Los valores de retorno del mock pueden diferir de los reales. Por ejemplo, puede devolver un tipo distinto con atributos diferentes.
-
Los efectos secundarios y comportamiento del mock pueden diferir del objeto real. Quizás el mock no lanza una excepcion que el objeto real sí lanzaría.
Alternativas a mockear
“¿Estás diciendo que mockear es malo y no deberíamos mockear?” No.
Depende de lo que estés “anulando”.
- ¿Es tu lógica de dominio de negocio lo que estás mockeando? Entonces está mal.
- ¿Es la conexión a la BD lo que estás mockeando? Entonces está bien.
Depende del contexto de la lógica y dónde pertenece esa lógica.
¿Es parte de tu lógica de dominio de negocio? Entonces no deberías mockearla sino instanciarla.
¿Es una dependencia de infraestructura como conexión a BD, sistema de archivos, red, o cualquier servicio externo que no tiene que ver con tu dominio de negocio? Entonces mockéala usando abstracciones/interfaces.
La interfaz es el contrato entre tu lógica de dominio y sus dependencias de infraestructura. Imagina lo fácil que es testear tu dominio instanciándolo y llamando a sus métodos con diferentes argumentos, todo bajo tu control total.
Algunos trucos
Cuando estés escribiendo un test unitario:
- Intenta instanciar tus clases primero.
- Evita mockear clases concretas. Escribí un artículo exclusivamente sobre esto: fomentando clases finales e interfaces.
Mockea interfaces. Instancia clases concretas.
“El uso excesivo de mocks lleva a código legacy.” — Philippe Boargau
¿Cómo podemos evitar el mocking excesivo?
- Favorece el estado inmutable sobre el estado mutable.
- Haz las dependencias explícitas.
- Programa hacia una interfaz, no hacia una implementación.

Referencias
- Mocking is a code smell — Eric Elliott
- When to mock & Test Definitions — Uncle Bob
- Final classes by default — Matthias Noback
- The problem with mocks — Sean Hammond
- A Set of Unit Testing Rules — Michael Feathers