Está en la página 1de 26

QUnit Cookbook En Espaol

david rene comba lareu


This book is for sale at http://leanpub.com/qunit-cookbook-espanol This version was published on 2012-11-22 This is a Leanpub book. Leanpub helps authors to self-publish in-progress ebooks. We call this idea Lean Publishing. To learn more about Lean Publishing, go to http://leanpub.com/manifesto. To learn more about Leanpub, go to http://leanpub.com.

2012 Leanpub

Tweet This Book!


Please help david rene comba lareu by spreading the word about this book on Twitter! The suggested hashtag for this book is #DevNod . Find out what other people are saying about the book by clicking on this link to search for this hashtag on Twitter: https://twitter.com/search/#DevNod

ndice general
Introduccin Automatizacin de unit testing Asserting Results Llamadas de retorno sincronicas Llamadas de retorno asincronicas Testeando acciones de usuario Manteniendo los tests atmicos Agrupando tests Desarrollo Eficiente 1 2 6 8 10 12 15 18 20

Introduccin
El testeo automtico es fundamental en el desarrollo de software. Unit tests son los bloques bsicos para armar tests automticos: cada componente, la unidad, del programa es acompaado por un test que puede ser ejecutado por un test runner una y otra vez sin intervencin humana. En otras palabras, puedes escribir un test una sola vez y ejecutarlo las veces que sean necesarias sin ningn tipo de costo adicional. En adicin a los beneficios de una buena cobertura de testeo, esto tambin puede definir el diseo de software, tambien conocido como test-driven design, donde el test es escrito antes de la implementacin. Puedes escribir un test muy simple, verificar que falla (por que el cdigo a testear todava no existe) y entonces escribir la implementacin hasta que pase el test.Una vez que eso sucede, puedes extender el test para cubrir mas funcionalidades deseadas e implementar otra vez.Repitiendo estos pasos, el cdigo resultante es muy diferente al que se obtiene si se empezara por la implementacin. Unit testing en JavaScript no es muy diferente de otros lenguajes de programacin. Lo que necesitas es un pequeo framework que provea un entorno ejecutor de tests (test runner), ademas de algunas utilidades para escribir los tests.

Automatizacin de unit testing


Problema
Si quieres automatizar el testeo de tus aplicaciones y frameworks, o tal vez beneficiarse del test-driven design, escribir tu propio testing framework puede ser tentador, pero demanda muchsimo trabajo cubrir todos los detalles y requerimientos especiales de JavaScript para testear el cdigo en varios navegadores.

Solucin
Aunque hay otros unit testing frameworks para JavaScript, has decidido explorar Qunit. Qunit es el unit test framework de jQuery y es usado en una variedad de proyectos. Para usar Qunit, solo debes incluir 2 archivos de Qunit en tu pagina HTML. Qunit consiste de qunit.js, el ejecutor de tests y test framework y qunit.css, que son los estilos usados para mostrar los resultados de los tests en la pagina.

Automatizacin de unit testing

Abrir este archivo en el navegador da como resultado lo siguiente:

El nico cdigo de maquetado necesario en el <body> es un <div> con id=qunit-fixture. Esto es necesario para todos los tests de QUnit, aun cuando el elemento mismo esta vaco. Esto provee el un lugar fijo para los tests, que ser explicado en la seccin llamada Manteniendo los tests atmicos. La parte interesante es el elemento *

Automatizacin de unit testing

Discusin
El encabezado de la test suite muestra el titulo de la pagina, una barra verde cuando todos los tests han pasado (una barra roja se muestra cuando alguno de ellos ha fallado), una barra con unos checkboxes para filtrar los resultados y una barra azul con el navegador, el userAgent (muy util para sacar capturas de pantalla de los resultados en diferentes navegadores). De los checboxes, Hide passed tests es til cuando se ejecutan muchos tests y solo algunos han fallado. Tildando la caja, se van a esconder todos los tests que hallan pasado, haciendo mas fcil el enfocarse en aquellos que fallaron (esto se explica en detalle en la seccin Desarrollo eficiente). Tildar Check for globals causa que QUnit haga una lista de todas las propiedades del objeto ventana (window object) antes y despus de cada test, y chequear las diferencias despus de cada uno.Esto ayuda a estar seguro de que tu cdigo de testeo y el cdigo dentro de este, no exporte ninguna propiedad al mbito global. El No try-catch checkbox le dice a QUnit de probar el cdigo por fuera de un bloque try-catch. Cuando el cdigo tire una excepcin, el ejecutor de tests morir. siendo incapaz de continuar pero se consigue como resultado una excepcin nativa, que puede ser de gran ayuda en navegadores viejos donde el soporte para manejar excepciones es deficiente (como en internet explorer 6). Debajo de la cabecera esta el sumario, mostrando el tiempo total que tomo ejecutar todos los tests como tambin el total de tests que han pasado y fallado. Mientras todava existan tests que se estn ejecutando, se mostraran sus nombres.

Automatizacin de unit testing

El contenido actual de la pagina van a ser los resultados de los tests, cada entrada en la lista empieza con el nombre del test, seguido por, en parntesis, el numero de tests que han pasado, que han fallado y el numero total de assertions. Clickeando cada entrada va a mostrar los resultados de cada assertion, usualmente con detalles sobre el resultado esperado y el obtenido. El link Rerun al fondo de cada test se usa para re-ejecutar ese test nicamente.

Asserting Results
Problema
Un elemento esencial de cualquier unit test son las assertions. El autor del test debe expresar el resultado esperado y hacer que el unit testing framework lo compare con lo valores que la implementacin produce.

Solucin
QUnit provee de 3 assertions. ok( truthy [, message ] ) El mas bsico es ok() que solo requiere de 1 argumento. Si la evaluacin del argumento resulta positiva (true) la assertion pasa, si en cambio resulta con otro resultado, falla. Tambin acepta como parmetro opcional un texto para mostrar en los resultados del test:

equal( actual, expected [, message ] ) La assertion equal usa el operador simple de comparacin (==) para comparar los resultados actuales con los esperados. Cuando son iguales, la assertion pasa, de otra manera, falla. Cuando falla, tanto el resultado esperado 6

Asserting Results

com el recibido son mostrados en los resultados del test, ademas del mensaje suministrado como tercer argumento. ![]images/img4.jpg) Comparado con ok(), equal() hace mucho mas fcil depurar tests que han fallado, por que es obvio que valor causo que el test fallara.Si fuera necesario una comparacin estricta (==), se puede usar strictEqual(). deepEqual( actual, expected [, message ] ) La assertion deepEqual() puede usarse como equal() y es la mejor opcin en la mayora de las ocasiones. En vez de usar el operador de comparacin simple (==), este usa un operador mas especifico (===). De esta forma, undefined no equivale a null, 0 o una cadena vaca ( ). Tambin compara el contenido de los objetos, as {key: value} es igual a {key: value} cuando se comparan 2 objetos con identidades diferentes. deepEqual() tambin maneja NaN, dates, expresiones regulares, arrays, y funciones, mientras equal() solo chequea la identidad del objeto:

En el caso de que explcitamente no se quiera comparar el contenido de 2 valores, todava puede usarse equal(). En general, deepEqual(), es la mejor opcin.

Llamadas de retorno sincronicas


Problema
Ocasionalmente, diferentes circunstancias en tu cdigo puede provocar que las assertions nunca sean llamadas, causando de que el test falle silenciosamente.

Solucin
QUnit provee una assertion especial para definir la cantidad de assertions que contiene un test. Cuando el test se completa sin el numero adecuado de assertions, este fallar, sin importar el resultado de los otros assertions. El uso es muy simple, solamente llama a expect() a principio del test, con el numero de assertions esperadas como nico argumento:

Opcionalmente, la cantidad de assertions esperadas puede pasarse como segundo parmetro de test(): 8

Llamadas de retorno sincronicas

Ejemplo practico:

Discusion
expect() provee de la mayor herramienta al probar llamadas de retorno. Cuando todo el cdigo corre en el marco de la funcin de test, expect() no provee ningn valor adicional - cualquier error que no permita las assertions ejecutarse, va a causar que el test falle, por que el ejecutor de tests captura el error y hace fallar la unidad.

Llamadas de retorno asincronicas


Problema
Mientras que expect() es util para probar cdigo sincrnico, este falla cuando existe cdigo asincrnico. Cdigo asincrnico entra en conflicto en la forma que el ejecutor de tests lo pone en una cola de ejecucin y ejecuta los tests. Cuando el cdigo dentro del test framework comienza un timeout, un interval o un ajax request, el ejecutor del test va a continuar con el resto del test, y todos los otros test que le sigan, en vez de esperar por el resultado de la funcin asincrnica.

Solucin
En vez de envolver las assertions en un test(), debe usarse asyncTest() y llamar a start() cuando el bloque de testeo esta completo y listo para resumir:

Ejemplo practico:

10

Llamadas de retorno asincronicas

11

Testeando acciones de usuario


Problemas
Cdigo que depende de acciones iniciadas por el usuario no pueden ser testeadas simplemente llamando a una funcin. Usualmente una funcin annima esta adherida a un evento de un elemento Ej: un click, que debe ser simulado.

Solucin
Puedes disparar el evento usando la funcin de jQuery trigger() y probar que se produzca el comportamiento esperado. Si no quieres que eventos nativos del navegador sean disparados, puedes usar triggerHandler() para solo ejecutar los event handlers. Esto es til cuando se testea un evento de click, donde trigger() va a causar que el navegador cambie de locacin, que es difcilmente lo que se quiere en un test. Asumamos que tenemos un simple registrador de teclas que queremos probar:

12

Testeando acciones de usuario

13

Podemos manualmente disparar el evento keypress para ver si el registrador esta funcionando:

Discusin
Si tu manejador de evento no depende de ninguna propiedad especifica del evento, puede simplemente llamar a .trigger(eventType). Sin embargo, si tu manejador depende de alguna propiedad especifica del evento, es necesario crear un objeto de evento usando $.Event y setear las propiedades necesarias, como fue mostrado anteriormente. Es tambien importante disparar todos los eventos relevantes para comportamientos complejos como el arrastre, que requiere de un mousedown, por lo menos de un mousemove y un mouseup . Hay que tener presente que algunos tests que parecen simples, son en realidad, complejos Ej: un click es en realidad un mousedown, un mouseup y un click. Si verdaderamente es necesario disparar todos estos eventos depende del cdigo que este bajo testeo. Disparar solamente un click es suficiente en la mayora de los casos. Si eso no es suficiente, existen unas cuantas opciones en frameworks

Testeando acciones de usuario

14

para simular eventos del usuario: *syn: Es una librera sinttica de eventos que bsicamente maneja tipeo, clickeo, movimiento, y arrastre exactamente como un usuario real hara esas acciones. Usada por FuncUnit, que esta basado en QUnit, para testeo funcional de aplicaciones web. *JSRobot: Una herramienta de testeo para aplicaciones web que puede generar keystrokes reales mas que simplemente simular el disparo de eventos en Javascript. Esto habilita a que se disparen comportamientos inherentes en el navegador que de otra manera no seria posible. *DOH Robot provee una API que permite a los testers automatizar los UI tests usando real, cross-platform, inputs a nivel sistema.Esto te permite estar lo mas cerca posible de eventos reales de navegador, pero usa java applets para generar esto.

Manteniendo los tests atmicos


Problema
Cuando los tests son puestos juntos, es posible tener tests que deberan pasar pero fallan o tests que deberan fallar pero pasan. Esto es resultado de tests teniendo resultados invlidos por efectos secundarios de tests anteriores:

El primer append() aade un <div> que el segundo equal() no toma en consideracin.

Solucin
Usa el mtodo test() para mantener los tests atmicos, siendo cuidadoso de mantener cada assertion limpia de cualquier efecto secundario. Debes solo depender en un maquetado fijo, dentro del elemento #qunit-fixture. Modificando y dependiendo de cualquier otra cosa puede tener efectos secundarios:

15

Manteniendo los tests atmicos

16

QUnit va a resetear los elementos dentro de #qunitfixture despus de cada test, eliminando cualquier evento que existiera. Si usas solo elementos con esta estructura, no necesitas limpiar manualmente para mantener los tests atmicos.

Discusin
En adicin a #qunit-fixture y los filtros explicados en la seccin llamada Desarrollo Eficiente, QUnit tambin ofrece un parmetro llamado ?noglobals como en el siguiente ejemplo:

En un test normal, esto pasara como un resultado valido. Correr el ok() con el parmetro noglobals causa que el test falle, por que QUnit detecta que ha populado el objeto window. No es necesario usar este parmetro

Manteniendo los tests atmicos

17

todo el tiempo, pero puede ser til para detectar polucin dentro del namespace global que puede ser problemtico en combinacin con libreras de terceros. Tambin ayuda a detectar bugs en tests causados por efectos secundarios.

Agrupando tests
Problema
Has separado todos tus tests para mantenerlos atmicos y libre de efectos secundarios, pero quieres mantenerlos lgicamente organizados y ser capaz de correr un grupo especficos de tests por si solo.

Solucin
Puedes usar la funcin module() para agrupar tests:

El test que ocurre despus de la llamada a module() va a ser agrupada en ese modulo. El nombre de los tests va a preceder por el nombre del modulo en los resultados del test. Puedes usar ese nombre de modulo para seleccionar los tests a ejecutar (mira la seccin Desarrollo Eficiente).

Discusin
Ademas de agrupar tests, module() puede ser usado para extraer cdigo en comn de tests que estn en el mismo 18

Agrupando tests

19

modulo. La funcin module() usa el segundo parmetro opcional para definir las funciones a correr antes y despus de cada test dentro de ese modulo:

Puedes especificar el parmetro setup o teardown o los 2.Llamar a module() otra vez sin ningn argumento adicional va a simplemente resetear cualquier propiedad setup/teardown definida anteriormente en otro modulo.

Desarrollo Eficiente
Problema
Una vez que tu set de tests tarda mas que unos segundos en correr, quieres evadir perder un montn de tiempo esperando los resultados.

Solucin
QUnit tiene muchas caractersticas que puede solucionar eso.La mas interesante solo requiere de un click para ser activada. Clickea el tem Hide passed tests al principio de la pagina y QUnit solo va a mostrar los tests que fallaron. Eso solo no hace diferencia en velocidad, pero ayuda a concentrarse en los tests que fallan. Se pone mas interesante si se toma en cuenta otra caracterstica de QUnit, que esta habilitada por default y normalmente no se nota. Cualquier test que falla, QUnit guarda el nombre del test en sessionStorage. La prxima vez que corras la serie de tests, ese test que fallaba va a correr antes que todos los otros tests. El orden de salida no es afectado, solo el orden de ejecucin. En combinacin con Hide passed tests vas a poder ver el test que fallo al principio y lo antes posible.

Discusin
El re-ordenado automtico sucede por default. Esto implica que tus tests deben ser atmicos, como se discuti previamente. Si tus tests no lo son, vas a obtener errores aleatorios. Arreglar esto es usualmente la mejor opcin, 20

Desarrollo Eficiente

21

pero si estas verdaderamente desesperado, se puede setear QUnit.config.reorder = false. Ademas del re-ordenamiento automtico, hay algunas opciones manuales disponibles. Puedes volver a ejecutar cualquier test clickeando Rerun en cualquier test. Eso va a agregar un testNumber=N parmetro a la url del test, donde N es el numero de test que clickeaste. Puedes recargar la pagina para seguir corriendo ese test o usar el botn Atrs del navegador para volver a ejecutar todos los tests. Correr todos los tests con un modulo funciona de la misma manera, solo que eliges el modulo a correr desde el selector al principio de la pagina a la derecha. Va a setear un module=N en la url, donde N es el nombre encodeado del modulo.

Conclusion
Esta es una introduccion basica a QUnit, con las funciones mas importantes y mas usadas de este test framework. El contenido de este libro fue traducido al espaol a partir de lo publicado en la pagina de QUnit bajo la seccion CookBook (http://qunitjs.com/cookbook/) por las siguientes personas y con la siguiente licencia: This section was first published, under a non-exclusive license, as the last chapter in the jQuery Cookbook, authored by Scott Gonzlez and Jrn Zaefferer. As QUnit changed since the book was printed, this version is more upto-date. This work is licensed under a Creative Commons Attribution 3.0 Unported License.
http://qunitjs.com/cookbook/

Desarrollo Eficiente

22

Como la version original, esta traduccion posee la misma licencia anteriormente mencionada. La traduccion fue echa por David Rene Comba Lareu, para DevNod.com (http://www.devnod.com) con la unica intencion de brindar material tecnico en espaol.

http://www.devnod.com