Desmitificando los dobles de test: Mocks, stubs and friends

Si sientes curiosidad por Agile y eXtreme Programming, es muy posible que hayas escuchado en artículos y hablas que el testing es bueno, que es tu red de protección, que te hace más alto y más guapo, etc etc etc … con lo que probablemente hayas oído nombrar el término Mock o bien Mockear dependencias.

En el presente artículo, vamos a procurar aclarar un tanto más la terminología que hay tras este y otros conceptos de testing, partiendo de la sabiduría de entre los grandes: Martin Fowler.

Dobles de test

Fowler, en su artículo Mocks Aren't Stubs, nos hace ver la necesidad de desambiguar este término del que tanto se abusa en la literatura y sobretodo en frameworks, terminando por transformarse en algo equívoco y poco claro. Y es que terminamos llamándole a todo Mock, cuando tenemos una enorme pluralidad de lo que pasaremos a llamar de ahora en adelante, dobles de test.

Para comprenderlo mejor, vamos desde una definición que hace el propio Fowler y que deja claro en un inicio como es el propósito de los dobles de test:

Test doubles is a generic term for any kind of pretend object used in place of a real object for testing purposes

Así, un doble de test es sencillamente un objeto que empleamos en substitución de otro cuando deseamos efectuar un test y no deseamos romper o bien ir alén del sujeto bajo test (de ahora en adelante SUT).

Pongamos que deseamos probar parte del código que interacciona con el API de pagos de un tercero. Ejercitar este API todo el tiempo puede ser lento, de producirse algún fallo puedo llegar a meditar que es culpa de mi código y, además de esto, probablemente ni tenga libre una plataforma de pruebas contra la que poder ejecutar mis tests sin rascarme el bolsillo haciendo un pago cada vez.

Es precisamente por esto que resulta recomendable siempre y en todo momento probar en aislamiento el SUT. Este planteamiento, que semeja fácil de explicar, puede resultar bastante complicado en el escenario expuesto previamente si usamos APIs de terceros, con lo que necesito algún mecanismo que me deje contar con dobles, farsantes o bien remplazos de estas unidades que no deseo ejercitar a lo largo de las pruebas. Lo que necesito son dobles de test :)

Cuando estoy programando, entre los objetivos principales que debería tener siempre y en toda circunstancia es que el código que escriba sea lo más mantenible posible. Una forma de lograrlo es que el código sea expresivo, claro y fácil de leer y continuar (asimismo conocido como Clean Code). Con esto, deseo recalcar que la pretensión en el momento de programar es exageradamente esencial cuando desarrollamos código compartido en un equipo. En este sentido, en vez de llamar Mocks a todos y cada uno de los dobles de test, lo que vamos a hacer es examinar las diferencias sutiles que existen en todos y cada uno de ellos de los modelos y ver de qué manera podemos aprovecharnos de ellas para prosperar la expresividad del código.

Tipos de dobles de test

Conforme la clasificación de Fowler, podemos atener a múltiples géneros de dobles de test:

Dummy: Son dobles de test que se pasan allá donde son precisos para llenar la signatura de los métodos empleados, mas no intervienen de forma directa en la funcionalidad que estamos testando. Son sencillamente relleno.
Fake: Son implementaciones de componentes de nuestra aplicación que marchan y son operativas, mas que solo incorporan lo mínimo preciso para poder pasar las pruebas. No son convenientes para ser desplegados en producción, con lo que jamás van a ser usados fuera del campo de un test. En un caso así, un caso claro sería una base de datos en memoria.
Stubs: Conjunto de contestaciones envasadas que se van a ofrecer a resultas de una serie de llamadas a nuestro doble de test. Serían por servirnos de un ejemplo el resultado de una consulta a base de datos que puede efectuar un repositorio. Es esencial comentar que en esta clase de dobles solamente atendemos al estado que tienen estos objetos y jamás a su comportamiento o bien relación con otras entidades.
Mocks: Dobles de prueba que son capaces de examinar como se relacionan los diferentes componentes, dejando contrastar si un procedimiento específico ha sido invocado o bien no, qué factores ha recibido o bien cuantas veces lo hemos ejercitado. Si bien asimismo pueden devolver una contestación con un estado determinado, su foco se centra más en el análisis del comportamiento. Nos asisten a testar puesto que el paso de mensajes entre objetos.

Del mismo modo que pasa con los tests unitarios en los que todos y cada uno de los stacks de programación ya cuentan con su xUnit (jUnit para Java, nUnit para .NET, unittest para python, etc), asimismo podemos hallar multitud de frameworks o bien librerías para crear dobles de test.

Ahora veremos dos ejemplos de como utilizar Stubs y Mocks en JavaScript con Jasmine, puesto que ofrece un montón de funcionalidades interesantes para el trabajo con dobles.

Ejemplo de empleo de Stubs

En el próximo ejemplo podemos ver como, desde la definición de un repositorio para la consulta de usuarios en la BD, podemos crear un stub que nos deje interaccionar con este objeto sin conectar con la BD real.

Recordemos que deseamos que nuestros tests sean veloces y también independientes, conque cualquier tipo que se ejecute en la frontera o bien boundary de nuestro sistema, puede ser susceptible de ser sustituida por un doble de test en el momento de diseñar nuestra pruebas.

Para crear nuestro Stub, jasmine nos ofrece le procedimiento spyOn(…).and.callFake con el que podremos delimitar que cuando se llame a un procedimiento específico de un objeto, este devuelva una contestación envasada como resultado.

describe(Locked usuarios, () => undefined);

Como podemos ver, jasmine no hace ninguna distinción entre Mocks o bien Stubs, y los llama a todos Spy. Como nuestro objetivo es dejar clara nuestra pretensión lo máximo posible, podríamos crearnos nuestro procedimiento de definición del Stub (stubOn) y incorporar este plus de semántica al código.

Esta modificación no cambia en nada los tests que ya había incorporado, mas sí la manera en que se inician los valores ya antes de cada ejecución, con lo que el código va a quedar de la próxima forma:

describe(Locked usuarios, () => undefined);

Ejemplo de empleo de Mocks

De forma afín a los Stubs, podremos crear Mocks en jasmine, mas esta vez, vamos a tener la posibilidad de efectuar comprobaciones más orientadas a comportamiento, como son si se ha llamado o bien no un procedimiento, con qué valores ha sido llamado o bien cuantas veces.

En un caso así, para crear un Mock de nuestro repositorio, vamos a emplear jasmine.createSpyObj, la que deja acotar un esqueleto iniciado con una serie de métodos a los que invocar cuando estemos usando el Mock (saveToStorage y remove).

Con la pretensión de advertir las llamadas que se efectúan a este Mock, lo inyectaremos como dependencia al userService que hemos definidiso, asertando más tarde si se han efectuado o bien no las llamadas y qué valores se han pasado.

describe(Usuario registration, () => undefined);

Conclusión

Nuestros tests han de ser veloces, independientes, expresivos y comunicar la pretensión de forma clara y sucinta.

En el momento de crear tests que no dependan de otros cooperadores o bien aun de infraestructura externa como la BD, los dobles de test pueden ser nuestros mejores aliados.

Su empleo tanto para la administración del estado con los Stubs, como del comportamiento con los Mocks, son una herramienta más que no podemos olvidar en nuestro toolkit de Agile Developers.

Referencias

Mocks Aren't Stubs
Jasmine dos

hljs.initHighlightingOnLoad();

code.hljs undefined
@media only screen and (min-width: 768px) undefined
@media only screen and (min-width: 1024px) undefined

Asimismo te invitamos a

¿Qué herramientas usas para mecanizar las pruebas de software?: el interrogante de la semana

Venus.js, herramienta open source para ejecutar tests unitarios en Javascript

¿Preparar tus looks es una insensatez? Organizarlos es más simple en un dormitorio ordenado

– La nueva