martes, 31 de mayo de 2011

Dobles de pruebas en Python llegados desde España

PyDoubles

En un mensaje de ayer en la lista de TDD en español, el amigo Carlos Blé, autor de el único libro (que yo conozca) de TDD en español (y gratuito), anunció la publicación de su framework para Dobles de Prueba en Python, construido porque no encontraban en su equipo uno como lo que ellos buscaban, y también como ejercicio.

El framework se llama pyDoubles, y el proyecto está hosteado en BitBucket para quienes quieran colaborar o derivarlo (está publicado bajo licencia Apache 2.0).

Según explican en la documentación, pyDoubles sigue la nomenclatura propuesta por Gerard Meszaros (en su ya clásico libro xUnit Test Patterns) para clasificar los dobles de prueba en stubs, spies o mocks.

Resumiendo brevemente, en el entorno de las pruebas unitarias, los dobles nos permiten reemplazar dependencias externas (que no son las que queremos probar) por otros objetos que -sólo a efectos de la prueba- se comportan como los verdaderos, facilitando la prueba de el SUT (o sistema a probar, por sus siglas en inglés).

Uno de los ejemplos clásicos es usar un doble para la capa de datos de un componente, ya que al probar nuestra lógica no necesitamos un repositorio de datos real, porque es dificultoso de mantener pero además es mucho más lento que utilizar un objeto con la misma interfaz o protocolo, que simplemente me devuelve lo que espero en el contexto del test.

La diferencia entre stubs, spies y mocks es sutil y discutida usualmente en la comunidad (desde el famoso artículo de Martin Fowler "Mocks aren't Stubs"). Lo importante en este caso es que el framework soporta los tres tipos.

Como el sitio de pyDoubles está ahora en inglés, traduzco brevemente la introducción explicando las categorías:

STUB

Reemplaza la implementación de uno o más métodos en la instancia del objeto que juega como colaborador o dependencia, devolviendo el valor que explícitamente devolvemos en la prueba. El stub es un método, pero es común llamar stub también a una clase que los contiene. El stub no tiene ningún tipo de memoria.

SPY

Hace lo mismo que el stub, pero puede registrar los métodos que se llamaron durante la ejecución de la prueba y cómo fueron invocados. Se utilizan para verificar la interacción o comportamiento.

MOCK

Además de lo que hacen los stubs y spies, es más estricto en la especificación del comportamiento esperado del sistema a probar. Antes de llamar a cualquier método en un mock, la prueba debe declarar, usando el framework, qué métodos y cómo deben ser llamados para que este comportamiento se verifique por completo. De lo contrario, la prueba falla con una excepción "UnexpectedBehavior" (comportamiento inesperado).

 

Como ellos explican en la documentación no hay tipos de dobles "mejores" que otros. Los mocks son más estrictos y por lo tanto hacen que las pruebas que los usan sean también más frágiles (más susceptibles a fallar por cambios menores en la implementación). Los spies son más flexibles en ese sentido, pero no alcanzan cuando necesitamos especificar un comportamiento especial en gran detalle. El resultado es que usualmente se utilizan combinaciones de los tres.

En la práctica, como siempre, conviene siempre aplicar la solución más sencilla que funcione, usualmente empezando con stubs, y luego recurrir a spies o mocks tipos cuando la prueba lo requiere.

Para ver ejemplos del uso del framework, les recomiendo ir directamente a la documentación.