Thursday, March 12, 2015

Pruebas unitarias en Javascript y AngularJS

Cada vez desarrollamos más aplicaciones web donde el 80% de la misma es código fuente Javascript. El componente del servidor se convierte en un mero servicio de dato, casi siempre un simple servicio RESTful. La cantidad de clases y lógica en el lado cliente es cada vez más grande y compleja, y evidentemente será más propensa a fallar con cada actualización que reciba la aplicación.


Para disminuir la posibilidad de fallos en nuestras aplicaciones existe un paradigma que se llama Test-driven development, basado en pruebas unitarias.


Creo que, a estas alturas, todos los desarrolladores han escuchado algo acerca de Pruebas Unitarias (Unit Test - UT). Si es su primera vez entonces deberá comenzar leyendo alguno de estos enlaces y profundizar con otros:




Es muy probable que se encuentre entre los que sí han utilizado los Test Unitarios para sus desarrollos en el lado del Servidor pero me atrevería a apostar que muy pocos lo han utilizado en el lado Cliente de las aplicaciones, específicamente en Javascript y AngularJS.


Cierto?


Si es asi no se preocupe, aquí pretendo introducirlo en este fascinante mundo.


Las herramientas para UT están muy extendidas en el lado del servidor, lo mismo en .Net como en Java, usted podrá encontrar soluciones nativas en sus herramientas de desarrollo. Los IDE como Visual Studio, Eclipse y otros, se integran perfectamente con la herramientas de UT y facilitan su creación y ejecución.


Pero, qué hay en la otra orilla?


Esta es una pregunta que hacía tiempo me venía haciendo y confieso que cuando hace un par de años leí sobre el tema resultó más en desilusión que en otra cosa. Al menos donde lei comentaban que algunos proyectos que habían comenzado ya ni siquiera se continuaban desarrollando. Creo que tampoco se le estaba dando la importancia que requería, quizás por un problema de costos, quizás porque a casi todos les iba bien sin Pruebas Unitarias en Javascript, o quizás simplemente porque aún predominaban las aplicaciones con más del 50% de su código en el lado del servidor.


Pero en lo personal, vengo teniendo la fuerte sensación que el ciclo de desarrollo esta incompleto, que tenemos una mesa de 4 patas pero la estamos sosteniendo solo con 3. Que no se ha caído? - Cierto, pero nadie negará que una de 4 tendrá más soporte.


Observando el desarrollo de Angular en el último año he comenzado a ver que en muchos de sus códigos de ejemplo hacen uso de test unitarios y esto comenzó a llamar mi atención. Mi sorpresa ha sido grande al revisar nuevamente sobre el tema.


Los herramientas de UT para Javascript y Angular están muy evolucionadas, siendo tan flexibles y poderosas como las de sus homólogas en el lado del servidor. Incluso existen ya manejadores de dependencias y proyectos al mismo estilo de Maven y Gradle para los proyectos clientes.


Entre las principales herramientas están:




No obstante todas las anteriores son herramientas de las cuales podemos prescindir. Nosotros podemos usar directamente el framework para Pruebas Unitarias que más desarrollado está, cuyo nombre es Jasmine.


Jasmine  es un poderoso y flexible framework para pruebas unitarias en Javascript con tanta o más flexibilidad que cualquiera de los que usamos en el lado del servidor. Con una sintaxis bien simple e intuitiva.


A la memoria me vienen al menos 3 o 4 proyectos recientes en los que he tenido que hacer a mano “páginas de pruebas” para el código de Angular, tanto para la capa de servicio como para los controladores. Pues bien, esto ha llegado también a su fin.


También tenemos en angular el módulo ngMock que nos ofrece soporte para todas las tareas relacionadas pruebas unitarias sobre componentes de Angular.


Existe en GitHub un proyecto “semilla”, listo para usar, incluyendo muchas de estas herramientas ya preconfiguradas. En honor a la verdad creo que a pesar de sus facilidades tiene demasiadas cosas para mi gusto que realmente no necesitamos pues muchas veces tenemos nuestros propios entornos de desarrollo.


Yo realmente prefiero usar una versión pura y limpia de Jasmine. Estuve buscando en GitHub un proyecto semilla para ello y realmente no he encontrado uno exactamente como lo quiero, o me canse de buscar quizás. Entonces he creado un ejemplo básico conteniendo solo las bibliotecas requeridas de Jasmine, versión “standalone” y un par de ejemplos con pruebas unitarias Javascript puro y Angular: https://github.com/deisbel/angular-jasmine-standalone-seed


Cuales son los elementos más importantes de Jasmine que necesitamos utilizar? - Solo unos pocos:


  • Una copia de las bibliotecas de jasmine-standalone.
    Esto se traduce en simplemente descargarlas desde su sitio web y agregarlas a la carpeta raíz de nuestro proyecto.
  • Crear los test unitarios.
    Esto no es más que sentencias de código Jasmine en archivos javascript. Puede ubicarlos mezclados dentro del codigo fuente de la aplicacion o en una carpeta por separado en la raíz del proyecto.
  • Agregar una simple página html preparada para correr las pruebas. Por defecto suele tener el nombre SpecRunner.html.
    Pedir la pagina desde un navegador es todo lo que necesitará para correr los test y ver los resultados. Esta página deberá actualizarla para agregar las referencias a los archivos de pruebas que haya creado y que desea correr.
  • Si además desea hacer test unitarios a los componentes de su aplicacion en Angular deberá agregar en la página referencias a las bibliotecas de angular y angular-mocks.


Para ilustrar cuán simple sería escribir un archivo para crear test unitarios usaremos la siguiente clase Persona, objetivo de nuestras pruebas.




Y definamos tres simples test que verifican que siempre se instancian correctamente sus propiedades y se obtenga bien el nombre completo de la Persona. Son pruebas unitarias bastante simples pero suficientes para nuestro propósito de ilustrar cuán sencillo puede ser. Para una referencia completa de lo que puede hacer con Jasmine debe remitirse a su pagina web.




Cómo debemos definir nuestro archivo SpecRunner.html para correr todas estas pruebas?


Quedaría así:




Note como existen dos secciones que deben actualizarse con cada archivo donde tenga pruebas unitarias definidas y los archivos que contengan clases que sean usadas por las pruebas unitarias. No es necesario incluir todos los archivos javascript del proyecto, solo los que nos interesan.


Una vez ejecutado en un navegador se vería así:




Hasta aquí lo más simple, solamente probando código puro de Javascript, pero, cómo lo hago si quiero hacer pruebas unitarias a un código de Angular?
- Basta con agregar un par de referencias a angular.js y angular-mocks.js en el archivo SpecRunner.html




De paso ya puede ver que agregamos un par de referencias más, una al archivo donde esta definido el Controlador que queremos probar y una al archivo donde están definidas las pruebas unitarias para este. El contenido de estos archivos es el siguiente:






Si ahora refrescamos la página SpecRunner.html para correr las pruebas nuevamente veremos estos resultados:




Puede agregar más archivos con clases y pruebas a medida que los vaya necesitando.


Espero que después de este artículo no tengamos más pretextos para no usar pruebas unitarias en lado del cliente y podamos cerrar un circulo que por momentos se resistía. Con esto lograremos hacer los módulos de clientes en Javascript más fiables y menos propensos a errores durante su desarrollo y posteriores actualizaciones.


Para profundizar en el tema le dejo los principales enlaces:




Para descargar el proyecto completo y colaborar:
https://github.com/deisbel/angular-jasmine-standalone-seed