sábado, 7 de diciembre de 2013

Preparando nuestro proyecto para pruebas unitarias (TDD)

Parece que hasta ahora hemos dado montones de vueltas antes de empezar a hacer nuestra app, y creanme aun no terminamos, y es que así es más parecido a la realidad.

Hoy vamos a iniciar entendiendo un tema útil y hasta de moda. Como vieron en el anterior post, la estructura de nuestra solución tiene un proyecto de test unitarios y la arquitectura necesaria para poder usarlos. Pues bien antes de eso y para los que no conocen hay que mencionar que es TDD (Test Driven Development)

TDD es una técnica para diseñar software que se centra en tres pilares fundamentales:

  • La implementación de las funciones justas que el cliente necesita y no más.
  • La minimización del número de defectos que llegan al software en fase de producción.
  • La producción de software modular, altamente reutilizable y preparado para el cambio.
Los invito a conocer en detalle sobre el tema con el libro de Carlos Blé, Diseño Ágil con TDD
Ahora bien, hacer TDD no es hacer pruebas como lócos es hacer pruebas con sentido, que ayuden a proteger a nuestro código  de cambios no inápropiados y a estar seguros que al menos cierta parte del mismo funciona correctamente.
Hay que entender que este tema es opcional pero es una buena práctica que vale la pena comentar y aplicar si trabajamos en equipos ágiles. Veamos como lo estamos aplicando en nuestro proyecto de Congreso Visible.

En mi óptica las Vistas Modelo deben quedarse intáctas y no deben tener mocks, los mocks son de fuentes externas o servicios de plataforma especificos tales como settings o caracteristicas del teléfono o tableta, que no estarían disponibles al ejecutar las pruebas unitarias, por esta razón el punto de partida es pensar que tipos de servicios tendremos y por tanto cuales son las interfaces de estos.

Confieso que me demoré más de lo que pensaba montando la estructura de todo esto, la parte positiva es que además de que quedo listo y super desacoplado, ustedes ya lo pueden descargar, verlo y explorarlo. Tenemos solo con un test case inicialmente, pero quedará super listo para ensamblar los demás. Vamos a ver si logro describir las cosas que tuve que hacer.

Lo primero que hice fue definir todas las interfaces de servicios que creo voy a utilizar.


Como ven además definí interfaces para las vistas modelos. Esto pudo perfectamente ser opcional, pero en la idea de intentar desacoplarme de todo fue un buen ejercicio que espero tenga algún proposito más que solo complicarme la implementación, ya que como claramente lo deben intuir las interfaces de las vistas modelos las debe implementar cada una de las vistas modelo que teniamos definidas, por lo que fue necesario trasladar todas las propiedades a las interfaces para que esten disponibles en los test cases y por supuesto realizar la implementación de las propiedades así:


Una interfaz que espero esten notando y se pregunten que es es IBindableServiceLocator. Si recuerdan la el post donde definimos la arquitectura, BindableBase que es quien implementan todas las VistasModelos, tiene un método que recupera del Services Locator, las instancias del servicio a usar. Pues bien, debido a mi uso de interfaces por aquí por allá debemos implementar una interfaz con este método para que así los test unitarios puedan reconocerlo pero recuperando el servicio falso.


Tenga en cuenta por lo tanto que nuestras interfaces de las Vistas Modelo ahora tendrán que implementar tambien IBindableServiceLocator.


Todo esto es un poco pesado al inicio para el esquema mental de quienes apenas están comenzando, pero tengan en mente que algún día lo comprenderán facilmente. Bien, por supuesto espero que sobre decir que además fue necesario crear todos los servicios Fake que probaremos y para eso era el proyecto de FakeServices.


Para entender un poco más por que todas estas complicaciones desde hace ya 5 post, vamos a ver el test case que implementé aquí. Para ello tenemos que conocer la nueva clase TestContainer que implementé dentro del proyecto de test, esto como ensayo no más, en el futuro espero tener varios TestContainer de acuerdo a grupos de pruebas que quiera hacer.


Por el momento, esta clase será la responsable de instanciar las Vistas Modelo y además de registrar los servicios falsos para las pruebas unitarias.


Ahora vamos a realizar la implementación del comando en nuestra Vista Modelo de ejemplo para crear el Test ShareProfile. En este punto está la magía y lo bonito del desacomplamiento, como ven nadie conoce a nadie, solo se usan interfaces. Por lo demás es solo la implementación de un comando, si no lo tienen claro, les recomiento como siempre ver los videos del maestro Josue Yeray explicando MVVM


Por último el lugar donde queríamos llegar es el test case o prueba unitaria. Empecemos por hacer un test que falle. Veamos ¿Por qué falla este test?


Espero que lo hayas adivinado, simple, por que no hay un enlace para compartir, así que al ejecutar los testcase el resultado es...


Usar un contador es una de las estrategias para hacer test, tambien podemos usar Callbacks y de hecho lo veremos en post más adelante pues será la estrategia con la que continuaremos haciendo TDD en nuestro proyecto.

Ahora como manda, hagamos funcionar el test


Y entonces después de todo este trabajo tenemos un bonito "Test case passed!", y la alegría que eso produce es solo apta para geeks! ;)


Si observaron con detenimiento, los mocks los implemento a nivel de Servicios solamente. ¿Por qué entonces hacer interfaces de las vistas modelo? Diría que es un tema de gusto por perseguir el desacople, si analizan o intentan eliminar las interfaces, se darán cuenta que el proyecto de Contratos, quedaría acoplado al de Vistas Modelo y bueno este a su vez estará acoplado al de servicios, así que nó, no es eso lo que persigo :)

Para no perdernos del contexto de nuestra app, aquí les dejo el Modelo de Paquetes actualizado. Sorpréndanse de todo lo que hemos creado y solo es infraestructura.


Entiendo que algunos de ustedes pueden necesitar hacer TestCases sin tener una arquitectura tan elaborada así que no olviden visitar MSDN para saber como ejecutar test incluso cuando los tienen al interior de la app de Windows Phone.

Actualización: He creado un post donde se usa un Test en un proyecto Windows Phone Unit Test para probar la navegación del NavigationService no olviden pasar a verlo, está al final y necesita de lo creado en ese post para ensamblarlo y entenderlo.

No hay comentarios: