Desde que empezamos a meternos en el mundo XP hemos intentado tener siempre muy presentes los tests. El código que escribimos es principalmente Java, y hemos estado intentando, con mayor o menor éxito, que no hubiera código sin su test, preferiblemente escrito primero.
Sin embargo, en mi equipo de trabajo nos hemos centrado bastante en el desarrollo de algunas aplicaciones web y me di cuenta de que no le teníamos el mismo ‘respeto’ al código Javascript que al código Java y ¡no nos habíamos planteado escribir tests para esa parte! Hay que decir en nuestra defensa que el código Javascript escrito hasta ese momento podía catalogarse de bastante sencillo, no llevaba mucha lógica con mucha lógica y se apoyaba principalmente en componentes JQuery.
La cosa es que no iba a quedarme tranquila hasta que investigara el tema de pruebas de Javascript.
Iba a empezar a trastear un poco con QUnit, cuando en un code retreat Xavi Gost (@XaV1uzz) me dijo que a él Enrique Comba (@ecomba) le había recomendado utilizar Jasmine, así que con esas recomendaciones merecía la pena echarle un ojo!
Jasmine es un framework estilo BDD para probar código Javascript. Y como a andar se aprende andando, nada mejor que empezar con un ejemplo sencillo para ir viendo su funcionamiento.
Como acostumbro a trabajar con maven hice una búsqueda para ver si encontraba algo que me facilitara una primera integración y encontré lo mejor que podía encontrar, ¡un arquetipo con ejemplos de uso!
En https://github.com/searls/jasmine-maven-plugin está la documentación del plugin de maven y del arquetipo.
Para empezar, necesitamos crear un proyecto a partir del arquetipo. En la página del plugin indican cómo crear un proyecto por línea de comandos, yo voy a hacerlo usando Netbeans.
Para crearlo vamos al menú File->New Project y seleccionamos Maven->Maven Project y seleccionamos añadir un nuevo arquetipo con los siguientes datos:
Group Id: searls
Artifact Id: jasmine-archetype
Version: 1.0.1-SNAPSHOT
Repository: http://searls-maven-repository.googlecode.com/svn/trunk/snapshots
El pom.xml que se nos crea es bastante sencillo de entender puesto que únicamente nos añade los repositorios necesarios, el maven-war-plugin para la generación del war con todos los ficheros y la configuración del plugin de Jasmine. La explicación de los goals que vienen configurados se encuentra en la página del plugin.
En la carpeta Other Sources tenemos una carpeta javascript. Dentro de esta carpeta es donde pondremos todos los ficheros javascript que usemos y que queramos probar. Si quisiéramos utilizar librerías como JQuery tendríamos que meter bajo esta carpeta también sus ficheros, no importa la jerarquía de carpetas que se cree ya que se cargarán todos los ficheros javascript que se encuentren dentro de ellas.
En la carpeta Other Test Sources hay otra carpeta javascript en la que pondremos los ficheros javascript con las especificaciones(specs) y las pruebas de nuestro código.
Con el arquetipo se crean unos ficheros que pueden servir como ejemplos, pero yo prefiero practicar con una kata y para la ocasión he seleccionado la String Calculator.
El primer requisito es que creemos el método add que reciba una cadena con cero, uno o dos números separados por una coma y el resultado sea ‘0’ si no hay números, el número si se pasa unicamente uno y la suma si se pasan dos números separados por una coma.
Tomamos la parte más sencilla del requisito: Devolver ‘0’ al recibir una cadena vacía.
Para comenzar creamos un fichero javascript para las especificaciones en la carpeta ya indicada. En él creamos una suite para agrupar los tests relacionados con nuestro StringCalculator. La forma de crearla es usando la función describe():
describe(‘string_calculator’,function() {
//Aquí añadimos las especificaciones
})
Y creamos nuestro primer requisito. Para ello utilizamos la función it() que recibe una cadena con la descripción de la funcionalidad requerida y la función a ejecutar.
it(‘devuelve 0 cuando recibe una cadena vacía’,function(){
var resultado = Add(”);
//Aquí van las comprobaciones de los resultados esperados
});
Para las comprobaciones del código esperado se utiliza la función expect() seguido de algún matcher de los que se encuentran en la página de la documentación. De esta forma la prueba para esta especificación quedaría:
describe(‘string_calculator’,function() {
it(‘devuelve 0 cuando recibe una cadena vacía’,function(){
expect(Add(”)).toBe(0);
});
})
Le estamos indicando que esperamos que el resultado de Add(”) sea ‘0’. Si ahora le damos a test sobre el proyecto veremos que en la salida aparece fallo de compilación, indicando que hay fallos en las especificaciones de Jasmine. Si leemos la salida podemos ver el error que ha dado:
it devuelve 0 cuando recibe una cadena vacía <<< FAILURE!
* ReferenceError: “Add” is not defined.
También podemos ver la salida producida en el archivo target/jasmine/ManualSpecRunner.html.
Como no hemos definido el método Add no puede encontrarlo. Así que vamos a crear un fichero Javascript en Other Sources/Javascript con dicho método. Definimos en él la función Add(cadenaASumar), pero lo dejamos de momento vacío y volvemos a ajecutar los tests, si actualizamos ManualSpecRunner.html vemos que el error ha cambiado y lo que no sindica es que no se obtiene el resultado esperado.
Para arreglar el test lo más sencillo es que hagamos que el método devuelva siempre ‘0’, quedando el código
function Add(cadenaASumar) {
return 0;
}
Y para comprobar que funciona no hace falta que volvamos a ejecutar la opción de test, únicamente bastará con que actualicemos ManualSpecRunner.html y como únicamente hemos actualizado ficheros que ya teníamos creados en javascript se actualizan todos los cambios, ¡y por fin vemos un bonito verde como resultado!
Creo que ya ha quedado bien introducido Jasmine, así que como tarea os dejo que probeis a continuar la kata.
En próximas entradas una futura entrada intentaré poner una solución a la kata.
¡Un saludo a todos y a practicar!
Mola!
Para otro artículo… estaría genial ver ejemplos de uso de Jasmine con pruebas de manipulación del DOM y AJAX (http://pivotal.github.com/jasmine/related.html) que es dónde yo tengo más problemas con javascript.
¿Podría ser una alternativa a los tests end-to-end (Selenium, webrat, etc…) para asegurar que la interfaz web no se ha roto?
Hola!
No te preocupes que tenía intención de hacer una segunda parte con ejemplos de uso del dom. Si quieres proponer algún ejemplo para que lo use como guía será bien recibido! Este primer post quería que fuera una introducción para los que no habían visto nada de esto antes, para ayudarles a arrancar.
A lo de si serviría para sustituir a Selenium… no creo ya que estos tests por lo que he podido ver de ellos no están pensados para ejecutar la parte servidora, la transición de páginas, etc. Yo creo que la idea de esta herramienta es aislar un poco la parte cliente y la parte servidora
Pingback: Propósitos para el 2011 « No es sólo cosa de hombres…