Está en la página 1de 16

QUnit es una completa suite para testear nuestras aplicaciones

Javascript desarrollada por el jQuery Team. En principio fue


concebida para usar sobre el propio cdigo jQuery pero su
flexibilidad permite integrarla fcilmente en cualquier desarrollo
tanto en cliente como en su versin servidor (Rhino, V8,node.js).
QUnit utiliza para comprobar el funcionamiento del cdigo la
metodologa conocida como Prueba Unitaria.
Concepto de prueba unitaria
En programacin, una prueba unitaria es una forma de probar el
correcto funcionamiento de un mdulo de cdigo. Esto sirve para
asegurar que cada una de las partes que integran nuestra aplicacin
funcionen correctamente por separado.
Las ventajas de las pruebas unitarias frente otras formas de test son
el que pueden aplicarse de una forma automatizada con antelacin a
la puesta en produccin de un cdigo. Esto quiere decir que no es
necesario el reproducir de forma manual todo el flujo necesario que
lleva a la obtencin del dato a verificar sino que en su lugar,
delegamos esa tarea a nuestro framework de pruebas. Una ventaja
aadida para los desarrolladores web es que pueden reproducir las
bateras de test en cada uno de los diferentes navegadores de una
forma casi desatendida. En caso de encontrarse un problema, como
las pruebas se ejecutan aisladas, llegar al error resulta ms sencillo.
Una vez reparado, se vuelven a ejecutar los tests para comprobar la
integridad en el resto de la aplicacin.
En cuanto a la calidad de nuestro cdigo, Javascript es un lenguaje
muy apto para la refactorizacin. Al tratarse de un contenido que
tiene que ser previamente descargado en cliente y ejecutado sobre
una amplia variedad de plataformas, es imprescindible alcanzar el
mayor rendimiento con el menor nmero de lneas posible. Para esta
etapa en el desarrollo, contar con una batera consistente de test
puede resultar de gran ayuda. Tras cada pequea modificacin del
cdigo durante la refactorizacin, es muy recomendable lanzar los
tests para comprobar que se mantienen las funcionalidades
esperadas.
El magnfico libro de Carlos Bl Jurado, Diseo gil con TDD, liberado
bajo licencia Creative Commons y descargable desde su pgina
oficial, explica en su captulo IV el concepto de test unitario a travs
de sus caractersticas:
Atmico. Significa que el test prueba la mmima cantidad
de funcionalidad posible.
Independiente. Significa que el test no depende de otros
para producir un resultado: funciona con independencia
de otros tests.
Inocuo. Un test nunca altera el estado del sistema. Su
ejecucin, por ejemplo, no crear nuevos ficheros o
registros en una base de datos.
Rpido. Debe realizarse lo ms rpido posible para no
interrumpir una dinmica de trabajo. Para el caso de
Javascript y las llamadas Ajax, esta caracterstica no
siempre puede alcanzarse debido a latencias y tiempos
de respuesta del servidor.
Todos los puntos anteriores conforman el acrnimo
ingls F.I.R.S.T con el que tambin pueden definirse las pruebas
unitarias: Fast, Independent, Repeatable, Small y Transparent.
Integrando QUnit en Javascript
Para comenzar a utilizar QUnit, solo necesitamos incluir en nuestros
ficheros dos archivos: un script con la librera y una hoja de estilos
(opcional) que permite una correcta visualizacin de los resultados.
<link rel="stylesheet" type="text/css"
href="http://github.com/jquery/QUnit/raw/master/QUnit/QUnit.css" media="all" />
<script type="text/javascript"
src="http://github.com/jquery/QUnit/raw/master/QUnit/QUnit.js"></script>
Como puede verse por las URLs, podemos elegir no guardar la
libreria en nuestro servidor y utilizar la ltima versin hospedada en
el repositorio pblico de github.
Si optamos por almacenar nuestra propia copia local, podemos
descargar ambos archivos desde lapgina oficial de QUnit.
Adems de estos archivos, nuestras aplicaciones tienen que contar
con una serie de etiquetas HTML donde se mostrarn los resultados
de nuestros tests:
<h1 id="QUnit-header">QUnit Test Suite</h1>
<h2 id="QUnit-banner"></h2>
<div id="QUnit-testrunner-toolbar"></div>
<h2 id="QUnit-userAgent"></h2>
<ol id="QUnit-tests"></ol>
Primeras pruebas
Cada uno de los bloques que componen nuestros test se llaman
afirmaciones (assertions). Una afirmacin puede definirse como un
estamento que evala el resultado de una determinada porcin de un
cdigo. Si el resultado obtenido es correcto (true), el test se supera;
si obtenemos un valor falso (false), el test no se supera.
Un test se compone de tres partes bsicas que se identifican
mediante las siglas
anglosajonas AAA :Arrange (Preparar), Act (Actuar) y Assert (Afirmar).
La preparacin es imprescindible antes de comenzar a evaluar
afirmaciones y su cometido es iniciar el contexto o marco de
pruebas.
En QUnit, utilizamos para ello la funcin test() cuya sintaxis es la
siguiente:
test( name, [expected], test )
Donde:
name (String) Nombre del test.
expected [opcional] (Number) Nmero de afirmaciones
que se esperan ejecutar. Lo veremos ms adelante; de
momento no lo usamos.
test (Function) Conjunto de afirmaciones que van a
evaluarse. Al menos, debemos contar con una.
Una vez realizado el SetUp, pasamos al acto donde llamaremos al
cdigo que queremos probar y que la terminologa denomina
SUT, Subject/System Under Test (objeto bajo test).
Finalmente, pasamos a la afirmacin, donde comprobamos que
el SUT (el objeto que estamos comprobando) funciona como se
espera.
En QUnit, la afirmacin ms bsica la proporciona la funcin ok(),
cuya sintaxis es la siguiente:
ok( state, message )
Donde:
state (Boolean) Expresin booleana o de cualquier otro
tipo que ser evaluada.
message [opcional] (String) Mensaje de salida que
acompaa el resultado de la afirmacin.
Es una afirmacin booleana, equivalente a assertTrue en JUnit. Si el
argumento obtenido es un valortrue, el test se supera.
Tomemos por ejemplo, la siguiente funcin:
function checkNumber( my_string ){
return ( parseFloat( my_string ) == my_string
? true
: false );
}
La idea es comprobar si el argumento que pasamos a la funcin se
corresponde con un nmero. Si se cumple la condicin, la funcin
devuelve true, para el caso contrario, obtendramos false.
Integremos ahora una serie de pruebas unitarias bsicas:
test( 'Testing checkNumber()', function() {
ok( checkNumber( 0 ) );
ok( checkNumber( 2 ) );
ok( checkNumber( -4 ) );
ok( checkNumber( 1 ) );
ok( checkNumber( 'asdf' ) );
ok( !checkNumber( 'asdf' ) );
} );
Para este caso, hemos escrito 6 afirmaciones de tipo booleano en el
que comprobamos el valor obtenido con cada llamada a nuestra
funcin (SUT).
Cuando cargamos nuestro archivo en el navegador, obtenemos lo
siguiente:

La afirmacin ok() equivale internamente a preguntar simplemente si
el SUT es true o false, por lo que podra desarrollarse de la siguiente
forma con idnticos resultados:
test( 'Testing checkNumber() with true', function() {
ok( checkNumber( 0 ) == true );
ok( checkNumber( 2 ) == true );
ok( checkNumber( -4 ) == true );
ok( checkNumber( 1 ) == true );
ok( checkNumber( 'asdf' ) == true );
ok( !checkNumber( 'asdf' ) == true );
} );
Afirmaciones ms flexibles
Las anteriores afirmaciones solo evalan un valor booleano, pero no
es difcil imaginar otros escenarios en los que se precisa mayor
flexibilidad. Pensemos en aquellos casos donde una funcin devuelve
un objeto, un literal u otra funcin. Para estos casos, contamos con
distintos tipos de afirmaciones de igualdad.
Tomemos ahora por ejemplo la siguiente funcin:
function areaTriangle( tBase, tHeight ){
return ( tBase * tHeight ) / 2;
}
En este caso, no obtenemos un valor booleano sino numrico y por lo
tanto, la funcin ok() no sera la ms adecuada. En su lugar, para
verificar que el resultado obtenido es el esperado, recurrimos a la
funcin equal(), cuya sintaxis es la siguiente:
equal( actual, expected, [message] )
Donde:
actual (Object) El objeto a evaluar.
expected (Object) El resultado experado.
message [opcional] (String) Mensaje que acompaa al
resultado de la afirmacin.
Bsicamente, el funcionamiento de esta afirmacin es el siguiente:
si actual == expected el test se resuelve correctamente.
test( 'Testing checkNumber()', function() {
equal( areaTriangle( 4, 3 ), 6 );
equal( areaTriangle( null, 3 ), 6 );
} );
El resultado obtenido con esta batera es el siguiente:

Una forma de mantener todos nuestros tests organizados
es definiendo mdulos que ms tarde podemos ejecutar de forma
unitaria. Para definir mdulos en QUnit utilizamos la
funcinmodule():
module( name, [lifecycle] )
Donde:
name (String) es el nombre del mdulo.
lifecycle [opcional] (Options) Permite
establecer callbacks que se ejecutarn tanto antes como
despus de cada test que compone este mdulo.
De este modo, podramos reunir los dos test anteriores en dos
mdulos independientes:
module( "Test Module A" );
test( 'Testing checkNumber()', function() {
ok( checkNumber( 0 ) );
ok( checkNumber( 2 ) );
ok( checkNumber( -4 ) );
ok( checkNumber( 1 ) );
ok( checkNumber( 'asdf' ) );
ok( !checkNumber( 'asdf' ));
} );

module( "Testing areaTriangle()" );
test( 'Testing checkNumber()', function() {
equal( areaTriangle( 4, 3 ), 6 );
equal( areaTriangle( null, 3 ), 6 );
} );

Afirmaciones Estrictas
Adems de las vistas anteriormente, QUnit permite otra serie de
afirmaciones como strictEqual odeepEqual.
strictEqual realiza una comprobacin estricta tanto de tipos de datos
como de valores. Su uso es similar a equal:
test('Comparing strict and no-strict modes', function() {
equals( 0, false, 'true');
same( 0, false, 'false');
equals( null, undefined, 'true');
same( null, undefined, 'false');
})
El resultado es similar al de las comparaciones bsicas en Javascript:

deepEqual realiza una comparacin recursiva perfecta para su uso en
objetos y arrays.
var o1 = {
'foo' : 'First Property',
'bar' : 'Second Property'
};
var o2 = {
'foo' : 'First Property',
'bar' : 'Second Property'
};

module( "Testing Recursive" );
test( 'Testing Recursive()', function() {
equal( o1, o2 );
strictEqual( o1, o2 );
deepEqual( o1, o2 );
} );

Ampliando funcionalidades de
QUnit
Recientemente han aparecido algunos interesantes proyectos que
pueden complementar las funcionalidades de QUnit como puede
ser Sinon.js.
Sinon.js es un framework completo para realizar bancos de test que
pose un plugin (sinon-QUnit) para integrarlo con QUnit.
Esta herramienta permite recoger los argumentos y los valores
devueltos por aquellas funciones que comprobamos para reutilizarlos
ms adelante. Toda la documentacin al respecto podemos
encontrarla en su pgina oficial.
Conclusin
Contar con un banco de pruebas consistente es una garanta de que
nuestras aplicaciones funcionarn correctamente antes de su puesta
en un entorno de produccin. Las ventajas de esta metodologa
frente a los mtodos tradicionales de ensayo y error son la capacidad
de reproducir de forma desatendida el comportamiento de un
usuario frente a la aplicacin final. En el desarrollo web, esta
flexibilidad es especialmente interesante cuando queremos
comprobar la respuesta del servidor ante un formulario enviado por
el usuario, una combinacin de eventos tediosa de repetir o una
arquitectura Javascript compleja.
Prcticamente todos los lenguajes de programacin modernos
cuentan con frameworks especializados en realizar este trabajo y
Javascript, dada sus caractersticas y su dificultad natural para
rastrear errores, no puede prescindir de uno. QUnit, desarrollado por
el equipo de jQuery es una fantstica opcin para delegar este
trabajo: su flexibilidad, basada en la misma librera jQuery, facilita la
integracin de plataformas de terceros que pueden aportar nuevas
funcionalidades.
En este artculo, hemos repasado parte de la teora que hay detrs de
las pruebas unitarias y las hemos aplicado al framework estudiado.
Con estas herramientas, estamos en disposicin de crear nuestros
propios tests y comenzar a disfrutar de los beneficios de esta
metodologa ntimamente ligada con eldesarrollo gil de software.