Uso de Mock objects en pruebas con Mockito

3
48955

Mockito

Introducción

Muchos de vosotros conoceréis TDD (Test Drive development), desarrollo
conducido por pruebas, donde la fuerza de nuestros programas se basa justo en
eso, en los test de las clases que vamos generando (De hecho TDD propone
generar los test antes de crear el c�digo de la clase).

Para poder crear un buen conjunto de pruebas unitarias, es necasario que nos
centremos exclusivamente en la clase a testear, simulando el funcionamiento de
las capas inferiores (pensad por ejemplo en olvidarnos de la capa de acceso a
datos, DAO). De esta manera estaremos creando test unitarios potentes que os
permitiría detectar y solucionar los errores que tengáis o que se cometan
durante el futuro del desarrollo de vuestra aplicación.

Para esta tarea nos apoyaremos en el uso de mock objects, que no son más que
objetos que simulan parte del comportamiento de una clase, y más
especificamente vamos a ver una herramienta que permite generar mock objects
dinámicos, mockito.

Mockito está basado en EasyMock, y el funcionamiento es prácticamente
parecido, aunque mejora el api a nivel sintáctico, haciéndolo más entendible
para nosotros (no existe el concepto de expected, para aquellos que sepáis algo
de EasyMock), y además permite crear mocks de clases concretas (y no sólo de
interfaces).

La idea de las pruebas al usar mockito es el concepto de stubbing – ejecutar
– verificar (programar un comportamiento, ejecutar las llamadas y verificar las
llamadas), donde centraremos nuestros esfuerzos, no en los resultados obtenidos
por los métodos a probar (o al menos no solo en ello), si no en las
interacciones de las clases a probar y las clases de apoyo, de las cuales
generamos mocks.

Vamos a ver el funcionamiento de mockito con diferentes ejemplos para asi
apreciar la funcionalidad y potencial de este tipo de herramientas.

Los siguientes ejemplos van a realizar mocks sobre listas (List),
simplemente porque la interfaz List es muy conocida y asi se facilita la
comprensión de dichos fragmentos de código. Quizás los ejemplos parezcan
demasiado simples o incluso poco lógicos, pero sólo los usaremos para
comprender e ir conociendo el api de mockito de una manera sencilla.

Recomiendo finalmente que os leáis las conclusiones para aclararos posibles
dudas.

Verificar el comportamiento

Una vez realizadas las llamadas necesarias al objecto que estamos probando
mediante mocks, vamos a comprobar que las iteraciones se han realizado
correctamente:

Una vez creado, el mock recuerda todas las interacciones. Se puede elegir
indiferentemente que interacción verificar

Stubbing

También podemos programar el comportamiento de los mocks, indicando qué
deben devolver ciertos métodos.

Por defecto todos los métodos que devuelven valores de un mock devuelven
null, una colección vacía o el tipo de dato primitivo apropiado.

Argument matchers

Los arguments matchers permiten realizar llamadas a métodos mediante
‘comodines’, de forma que los párametros a los mismos no se tengan que definir
explícitamente:

Argument matchers permiten realizar stubbing o verificaciones muy flexibles.
podéis ver mas en http://mockito.googlecode.com/svn/branches/1.7/javadoc/org/mockito/Matchers.html

Verficiando el numero exacto de invocaciones, al menos X, o
ninguna invocación

Vamos a ver ahora cómo verificar si se ha un cumplido un número mínimo o
máximo de llamadas al mock:

Stubbing metodos void methods con excepciones

Veamos ahora cómo realizar stubbing de métodos que no devuelven nada (por
ejemplo para indicar que deben lanzar una excepción):

Verificaciones en orden

Si necesitamos que varios mock necesiten llevar un orden específico en las
llamadas lo podemos realizar de la siguiente manera:

Realizar verificaciones en orden son muy flexibles. no es necesario
verificar todas las interacciones, si no sólo aquellas que necesitamos.

Asegurandonos que alguna(s) interaccion(es) nunca ocurren
en un mock

Buscando llamadas redundantes

Ojo! : verifyNoMoreInteractions() debe ser llamada solo cuando necesario.
Realizar llamadas a este método asiduamente (sobre todo en todas las pruebas)
generará test muy poco mantenibles y ampliables. Es mejor usar never() para
aquellos métodos que no deban ser interaccionados.

@Mock

Nos permite realizar mocks anotando el código, y así el mismo queda más
claro y limpio.

Importante! La siguiente llamada debe encontrarse en algun lugar de una
clase base o del test runner:

O se pueden usar como runners MockitoJUnitRunner, MockitoJUnit44Runner.
(veremos en otro tutorial un ejemplo).

Conclusiones

Como hemos podido ver en este tutorial, el uso de mock objects nos facilita
mucho crear test unitarios que no dependen de las capas inferiores, y por tanto
prueben las clases de cierta capamucho más exhaustivamente, permitiendo la
detecci&aoacute;n de errores y asegurándonos el buen funcionamiento durante
el futuro.

Algunos, tras ver los snippets de código anteriores pensaran… ¿y para qué
me sirve mockito?, ¿por qué ‘perder’ el tiempo usando mock objects cuando puedo
realizar las pruebas apoyandome en otras clases que ya han sido probadas, y
funcionan bien?. Es un error. Lo primero, NUNCA se pierde tiempo en generar
test ni en usar mock objects, puesto que ese código nos automatizará las tareas
de pruebas nos sólo durante el desarrollo, si no tambien durante las fases de
mantenimiento de la aplicación; y pensar que el código que hoy no falla no
puede fallar mañana es err&aoacute;neo también.. y si el fallo esta en las
clases en las que nos apoyamos.. nuestros tests fallaran cuando nuestras clases
(puede que) funcionen bien.

Ya véis que en Autentia nos gusta
trabajar bien, y con las últimas herramientas, que nos ahorren tiempo y
esfuerzo, asi que no dud&aeacute;is en contactar con nosotros para más
información.

3 Comentarios

  1. Hola Gemán, gracias por los aportes y a la empresa por los esfuerzos en propagar el conocimiento en nuevas tecnologías para ayudarnos en el día a día.

    Tengo una duda que me viene rondando desde que vi el tutorial, aunque no me he puesto a estrujarme la cabeza en probarlo…

    ¿Sería posible usar un mock en la ejecución de la aplicación sin tener que ejecutarse como parte de las pruebas unitarias?

    Que fuera el objeto necesario para la aplicación…

    Gracias,
    Un Saludo

Dejar respuesta

Please enter your comment!
Please enter your name here