Mockito 3: ¿Qué hay de nuevo?
Para quien no lo conoce, Mockito es un framework con base en Java para poder hacer tests de unidad. Te da muchas facilidades para poder hacer objetos “Mock” (“Falsos”) a los cuales les podemos dar acciones o pedir que se cumplan condiciones sobre ellos.
En este post vamos a repasar las principales novedades que tuvo Mockito, partiendo de la versión 1.8.X a la versión más actual hasta el momento 3.6.X, con el objetivo de que cada uno sepa que existen estas herramientas y luego las puedan usar o no, según su criterio personal.
En la versión 1.8.X (2009) nos encontramos con un framework muy robusto pero con algunas falencias. Hasta esta versión, Mockito no podía “mockear” objetos inmutables (final) ni métodos estáticos (static). Ambos, según el caso, pueden ser muy útiles a la hora de programar; pero, a veces, se debía abstener de usarlos para poderle dar a tu codigo mayor cobertura y testeabilidad, o usar librerías externas como PowerMock, que no son muy amigables.
Mockear Finals:
A partir de la versión 2.1.X (2016) se agregó la posibilidad de “mockear” objetos inmutables o “final”, consiguiendo poder usar estos objetos como una herramienta sin descuidar los tests. Una forma de usarlos es la siguiente, aplica tanto para clases como para métodos:
En este caso, el test funciona bien.
Como pueden ver en las imágenes, la “ClaseFinal” se puede “mockear” sin problemas usando el Mockito.mock(), cosa que antes de la versión 2.1.X daba error. Lo mismo sucede con el “metodoFinal”, a este se le puede dar comportamiento con el Mockito.when() sin ningún problema mientras que en el pasado no se podía.
La primera falencia de Mockito 1 se solucionó, ahora se pueden mockear cosas “final” con Mockito 2, pero aún nos queda otra de las carencias que tenía sobre los métodos “static”.
Mockear Statics:
A partir de la versión 3.4.X (2020) podemos ver que el framework incorpora una forma de poder “mockear” métodos “static”. Se puede hacer de la siguiente forma:
En este otro caso también, el test da OK.
Aca hay un detalle a tener en cuenta, para poder mockear métodos “static” se deben encapsular todos sus usos dentro de un try/catch ya que el objeto MockedStatic es el que nos va a permitir utilizar esta nueva funcionalidad.
Por un lado, parece raro tener que usar una estrategia diferente de encapsular parte de los tests; pero en contraparte, se gana una herramienta muy poderosa con la cual vamos a poder mejorar nuestros tests y hacerlos cada vez más unitarios, cosa que antes no lo podíamos hacer sin atarnos a librerías externas.
Mockear Constructores:
Una de las recientes mejoras que se agregaron en la versión 3.5.X (2020) es poder “mockear” constructores de objetos. Si bien esto no es lo más común a la hora de hacer tests de unidad, quizás pueda ser útil en algún que otro caso. Para hacerlo, se puede probar lo siguiente:
Este test se ejecuta correctamente sin errores.
Como pueden ver en este ejemplo, pasa algo muy parecido a cuando “mockeabamos” los métodos “static”. En este caso también, sólo podemos utilizar el mock de constructores dentro del bloque try/catch donde se contenga al objeto MockedConstruction como recurso del “try”. En caso que se haga afuera del try-with-resources, no va a tener efecto el mock y se va a llamar al constructor original.
Ahora, ¿qué sucede si llamo 2 o más veces al constructor de un objeto en mi test?
Para poder entender mejor el funcionamiento les propongo que hagan un seguimiento de este código en “modo debug” a ojo, donde los números indicados son el orden en que se van a ejecutar las líneas de código. Se ponen dos “when” para mostrar las diferencias que pueden presentarse en la ejecución:
Por supuesto, este test también da OK.
Vale la pena destacar que cuando se llame al constructor, recién en ese momento va a ingresar la ejecución en la función anónima del try-with-resources, donde se le va a indicar cual es el “when” para el objeto “mock”. Cada vez que entra a esta función, se utiliza un objeto “mock” nuevo, con lo cual cuando ingresa por el número 2 o el número 5 va a afectar a objetos “mock” diferentes.
Configuraciones:
Para concluir, les dejo las configuraciones necesarias para poder hacer que Mockito 2.1.X en adelante les funcione en sus proyectos. No alcanza con cambiar la versión en el POM (vale lo mismo para otros manejadores de dependencias). Para que estas funcionalidades se activen, se lo tiene que explicitar a Mockito, para esto hay dos opciones:
Opción 1) Agregar al POM la dependencia org.mockito:mockito-inline
Opción 2) Agregar un archivo de forma manual siguiendo estos pasos:
- Crear el directorio src/test/resources/mockito-extensions/
- En este directorio crear un archivo de texto que se debe llamar “org.mockito.plugins.MockMaker” tal cual esta dentro de las comillas.
- El archivo de texto debe contener únicamente: mock-maker-inline.
Curiosidades:
- A partir de mockito 2.1.X deja de funcionar la dependencia org.mockito:mockito-all y hay que utilizar la dependencia org.mockito:mockito-core.
- Powermock es compatible con Mockito 1.8.X pero a partir de mockito 2.1.X deja de ser compatible, además de que empieza a perder el sentido. Utilizando la versión 3.5.X de Mockito, se abarcan las principales características que solucionaba PowerMock.
- Migrar de mockito 1.8.X a mockito 2.1.X es costoso si se tiene una app grande que lo utiliza, conviene revisar artículos donde se especifican todas las cosas a considerar para la migración.
- Migrar de mockito 2.1.X a mockito 3.5.X es muy sencillo, solo varía algún que otro método deprecado que fueron reemplazados por otros métodos pero nada muy disruptivo.
- A partir de Mockito 2.1.X, los mocks comienzan a retener información de meta-data y tipos genéricos. Los mismos pueden ser pedidos por reflection a un mock.
- Al mockear los constructores, existe un objeto “context” dentro de la función anónima, al cual se le pueden pedir por ejemplo los parámetros en cada ejecución para validarlos. Dejo un mini ejemplo:
Documentación y Referencias:
- Javadoc: https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
Esta muy completo y con buen detalle de cada novedad que trae en sus diferentes versiones. MUY recomendable!! - Se puede mockear la construccion de un objeto (+3.5.0) https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#mocked_construction
- Mockeo de metodos estaticos (+3.4.0) https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks
- Se pueden mockear tipos finals, metodos finals y enums (+2.1.0) https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#Mocking_Final
- Mockito retiene meta-data y tipos genericos (+2.1.0) https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#Meta_Data_And_Generics