‏إظهار الرسائل ذات التسميات TDD. إظهار كافة الرسائل
‏إظهار الرسائل ذات التسميات TDD. إظهار كافة الرسائل

الجمعة، 10 يناير 2014

Controlando el estado de la red usando MVVM

Bueno, continuamos con nuestras labores de infraestructura, que bien podrían parecer muchas pero que a la vez nos dan la seguridad de construir sobre bases firmes. Recuerden que este post hace parte de la serie CongresoVisible.

El nuevo reto al que nos enfrentamos es un requerimiento típico de usuarios y clientes que piden aplicaciones, controlar que no se hagan solicitudes cuando el internet no esté disponible. Pues bien, si ya lo han intentado, se habrán dado cuenta que comprobar que el internet este habilitado antes de cada petición es bastante costoso, y bueno vamos a intentar una forma más elegante de hacerlo y además de incluirlo en nuestro proyecto.

Lo primero con lo que nos encontramos es que, el comprobar el estado de la red es particular a cada plataforma como lo fue la navegación que vimos en el post anterior. Así que, aunque tenemos la interfaz de nuestro servicio en el proyecto de contratos. El contrato hasta el momento se ve así:

Su proposito va a ser exponer una propiedad que nos diga el estado de la red y además exponer un método que nos comunique el estado de la red en el momento que esta cambie.

Bien, luego de eso y aprovechando que tenemos una interfaz compartirda en las view model que cumple con un proposito similar, agregamos una propiedad nueva, el NetworkMonitor, a través del cual accederemos al Internet Services a verificar el estado de la conexión desde cualquiera de las vistas modelo.

Cómo es de esperarse este NetworkMonitor será implementado por la clase que comparten todas nuestras view models, es decir BindableBase.


Ahora bien, como ya lo había mencionado, al tener que enfrentar este problema como algo puntual de cada plataforma, ubicaremos la implementación del servicio en nuestra carpeta local de infraestructura.


La implementación será la siguiente:


Esta es la clase que debemos implementar en cada plataforma. Si observan bien, lo que en realidad sucede es que al interior del servicio estamos suscritos a la clase de Windows Phone que nos comunica los cambios en el estado de la conexión. Cuando esto ocurre hacemos dos cosas, verificamos el estado de la red y cambiamos la variable de control, pero además si alguien está escuchando el evento que expuso nuestra interfaz entonces le comunicaremos que el estado de la red cambió.

Algo más que debemos tener en cuenta es que para que nuestras vistas modelo que necesiten conexión a internet tengan el NetworkMonitor disponible, debemos asígnarlo en el constructor del Locator quien ya sabemos al estar como recurso de la aplicación estará vivo desde el inicio.


Actualización: En post siguientes al intentar ensamblar la aplicación se identificó un faltante en este punto y es la inicialización la primera vez que se inicia el localor. La clase quedó así.


En la inicialización simplemente se llama el método que establece los valores de las variables.


Este lo hacemos a modo de ejemplo, puesto que como estamos haciendo TDD aprovecharemos este post para hacer los Test de conectividad de nuestra aplicación. Primero preparamos la Vista Modelo que vamos a probar con un método que solo va a usar el servicio de consumo de datos si la red está disponible. Algo sencillo como pueden ver:


El GetFilters del FakeJsonService recuerden no es más que un llamado al Callback


Luego de eso construimos los Test de conectividad


Si hacen debug a estos test notarán como en el primero de ellos, jamás se pasa por el Breakpoint, lo que es lógico, debido a que al no haber conexión a internet no se usa el servicio de consumo de datos que es lo que queriamos. Mientras que en el segundo test claramente el debug entrará al Callback por que la red está disponible.

No olviden, todo este código es un tanto confuso pero está disponible en mi Github para que lo vean con calma y por que no, me envíen sus sugerencias y correcciones.

الأحد، 8 ديسمبر 2013

Implementando el servicio de navegación usando MVVM

Uno de los retos básicos al tratar de hacer una buena arquitectura cross platform consiste en que la navegación en cada plataforma es diferente, si han intentado desarrollar en Windows Phone y Windows 8 van a notarlo facilmente, en Windows Phone por ejemplo el NavigationService es una clase que solo podemos usar a nivel de un proyecto de UI, así que, si recuerdan, nuestras Vistas Modelo en el proyecto que tenemos, están ubicadas en un proyecto diferente, persiguiendo el tema de ser lo más cross platform posible. Ese es un problema, además de que el NavigationService de Windows Phone de nada serviría compartido.

Para dejarles opciones quiero compartirles los enlaces que encontré con propuestas parar el tema, y en el transcurso de este post, explicaré la que elegí y como la incluí en CongresoVisible
  1. Alejandro Campos : Ejemplo de una implementación del patrón MVVM
  2. Sara Silva: Adding Navigation Service
  3. Josue Yeray: Cualquier código autogenerado por App Studio
La solución que elegí a este problema la plantea Nick Randolph, en su artículo Estados, Navegación y Testing en Clases Portables, allí pueden encontrarlo además de explicado detalladamente, libre de toda la arquitectura que estamos trabajando, por que ella nos pone en ciertas situaciones al intentar agregarla. Eso sí lo más importante es entenderla de forma básica, por que en nuestro proyecto quedará bastante dispersa.

Lo que más me gustó de esta solución es su sencillez pero que a la vez deja ser a cada plataforma lo que es sin complicarse demasiado y teniendo una estructura apta para test.

La primera parte que vemos de esta implementación es el Contrato del INavigationService


Es así de sencilla por que de hecho lo único que pretendemos reemplazar es justamente la opción de navegar, igual si tuviesemos otros tipo de necesidades en este lugar las añadiremos posteriormente.

Según nuestra arquitectura, esperaríamos que haya en el proyecto Services y en FakeServices alguien que implemente esta interfaz pero ahí viene la diferencia, como ya lo dijimos al ser un problema puntual de cada plataforma, esta clase se va a implementar en cada plataforma. Sin embargo el FakeService si puede implementarse para los test.


La implementación concreta propuesta para Windows Phone es la siguiente:


Esta es la implementación que cambiará para cada plataforma. Si intentamos entender este código, veremos como la ruta a la que se pretende navega es el nombre de una clase, esa clase serán nuestras vistas modelo, y claramente nuestras páginas no van a llamarse como nuestras vistas modelo, sin embargo, la propuesta de Nick si es hacerlas algo similares. Ella consiste en ubicar las páginas en una carpeta y nombralas según la Vista Modelo que representa su contexto.


Para que esta indicación cobre sentido, debemos continuar las instrucciones, la que sigue consiste en crear un Uri Mapper con una estrategia particular que Nick describe en otro de sus artículos.


Si observamos con detenimiento este UriMapper nos damos cuenta que se está usando una parte del nombre de la VistaModelo para ser mapeada contra una página, así es bastante sencillo de entender, claro está nos va a forzar a tener una Vista Modelo por cada vista a la que queramos navegar, pero eso no está tan mal, es más o menos lo típico. Para que esto termine de encajar debemos cambiar una línea en App.xaml.cs para establecer nuestro UriMapper en plena inicialización.


Ahora bien, si lo han estado notando, acompañando al NavigationService hay una clase más que teniamos pendiente por implementar para nuestras apps y es un Locator. Si recuerdan nuestros Test, en ellos la misma clase de Test inicializaba las vistas modelos, pues bien para teminar la implementación de nuestro ServiceLocator, necesitamos un Locator local que sirva como contexto a nuestras vistas, es aquí donde diferimos de la implementación que hace Nick en el artículo, debido a que nosotros tenemos un manejo de dependencias a través de nuestro ServiceLocator.

Pues bien, nuestro Locator quedaría implementado de la siguiente manera

Si analizamos la implementación vemos que este Locator es el responsable de inicializar las instancias particulares de los servicios y de las vistas modelo. ¿Pero como es que esta clase inicializa todo para la app? ¿En que momento lo hace?

Pues bien, el momento es cuando empieza a ejecutarse la aplicación, ya que si lo pasaron por alto, pueden observar que el Locator está definido como recurso de la aplicación en el App.xaml


Pero además siguiendo el patrón Service Locator, debemos hacer que cada una de nuestras vistas tenga como DataContext a este Locator que es un recurso, así:


Para terminar con nuestra implementación de navegación y si son lo suficientemente curiosos habrán notado que cuando el Locator instancia cada una de las vistas modelo y las registra en el Service Locator, además inicializa su Navigator.

Pues bien cada una de las VistaModelo que requiera usar el navigator ahora implementa la interfaz INavigateViewModel, con la que además hice un ajuste en el proyecto de contratos


Así pues de acuerdo a las capacidades que requieran las interfaces de nuestras vistas modelo tendrán que implementar estas interfaces


Pero entendiendo que las implementaciones concretas de estas son comunes a todas las vistas modelos, dejamos la implementación concreta en BindableBase de la cual tenemos certeza es heredada por todas nuestras vistas modelo


Estoy del desacople es literal como juga con legos. Ahora lo que queriamos ver desde el inicio es la navegación, estando todo listo para que pueda darse, ahora navegar desde nuestras vistas modelo es tan sencillo como esto.


Bastante bonito ¿eh? Para completar nuestra implementación haremos algo que Nick muestra en su post y es crear un proyecto de Test de Windows Phone, esto solo por el mero ejercicio ya que como saben tenemos nuestra estructura de pruebas listas para hacer lo mismo.

Lo primero que debemos hacer es crear un proyecto de Pruebas Unitarias para Windows Phone.


Como van a ver en el test que se implementa, no tiene nada particular como para dejarlo en un Test de este tipo, pero como les mencionaba en ese post, si su arquitectura no está tan segmentada como la mía, bien valdria la pena ver que tienen a la mano este tipo de herramientas.

Nuestro test usando comandos sería:


Incluí este test en nuestro proyecto de test general así:


Para quienes recién empiezan con los test observen como en cada uno de los que tenemos hasta ahora hay dos estrategias diferentes, uno es con un Callback y el otro con un contador, cada uno puede hacerlo como mejor lo entienda, lo importante es hacer los test.

Ese es el fin del ejercicio, espero no haber olvidado poner ningun paso, sin embargo el código está publicado. Estamos a punto de llegar al momento donde nuestra aplicación por fín hace algo y si que hemos trabajado. :)

السبت، 7 ديسمبر 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.