qUnit

Categories:

Es un framework que se utiliza para evaluar código. Es utilizado por jQuery, jQuery UI y jQuery Mobile.

Organizar archivos en qUnit

Primero descargamos los archivos qunit.css y qunit.js del sitio de qUnit.js.

qunitjs

Después hacemos un archivo html. Ese archivo va a ser el que vamos a visualizar en el navegador cuando se realicen las pruebas. Ahí hay que incluir la hoja de estilos y el archivo JavaScript que descargamos.

qunit configuración inicial

Una vez que tenemos los archivos listos vamos a crear las especificaciones.

qUnit organización de archivos
Organización de archivos para qUnit

Aunque no es necesario utilizar carpetas, es práctico separar las especificaciones del código fuente. Utilizo la carpeta src para guardar los archivos con el código fuente y la carpeta test para las pruebas, pero les puedes dar un nombre que tenga más contexto con tu flujo de trabajo.

Crear especificaciones

Para crear las especificaciones que van a evaluar el código fuente podemos seguir el siguiente proceso – mismo que se utilizó con jasmine y evaluar código – .

  1. Dentro de la especificación podemos crear un módulo.
    La creación del módulo es opcional, sirve para agrupar las pruebas que tienen características similares o que están dentro de un mismo contexto.
  2. Hay que crear las pruebas.
    Cada prueba es un bloque de código que comienza con la descripción de lo que esperamos que el código realice.
    Dentro del bloque creamos expectativas del resultado que se espera obtener cuando se evalúe el código.
    Es recomendable que cada prueba evalúe una funcionalidad en particular del código.
  3. Ahora tenemos que escribir el código para que cumplir con la expectativa.
    Si es necesario, debemos crear diferentes pruebas para evaluar la misma sección de código.
  4. Repetir los pasos anteriores por cada archivo de código fuente que vayamos a evaluar.

Módulos

Al definir un módulo con module todas las pruebas que se encuentren después de esa línea de código pertenecen al módulo.

Si existen más líneas definiendo módulos, las pruebas posteriores a la definición de cada módulo pertenecen este módulo.

QUnit.module("Primer módulo");
/*
  Aquí van las pruebas para el primer módulo
*/

QUnit.module("Segundo módulo");
/*
  Aquí van las pruebas para el segundo módulo
*/

Pruebas
Cada prueba es el lugar donde definimos lo que esperamos que haga el código, asignamos un valor esperado y comparamos el resultado obtenido de la evaluación del código con el resultado.

Si la comparación es satisfactoria, la prueba es considerada correcta. Si no pasa se muestra el mensaje definido junto el valor esperado y el obtenido para corregir el error.

test("Estructura de una prueba", function ( ) {  
  /*
    Dentro de la prueba se definen las expectativas  
  */
});

Afirmaciones

Cada afirmación nos permite comparar de manera particular el valor generado por el código fuente con el valor que esperamos obtener.
Algunas afirmaciones que podemos utilizar en qUnit son:

Afirmación

Descripción

Sintaxis

deepEqual

Afirmación recursiva de comparación que se busca que sean idénticos el resultado y la expectativa.

var obj = { 
  foo: "bar", 
  bar: "baz"
};

var obj2 = { 
  foo: "bar", 
  bar: "baz"
};

deepEqual(obj, obj2, "Los objetos deben ser idénticos. Deben de tener los mismos atributos y los mismos valores para los atributos.");

equal

Afirmación donde la comparación no es estricta, se busca que el resultado y la expectativa sean iguales.

var numero = 1;
var texto = "1";

equal(numero, texto, "El número y el texto deben tener el mismo valor.");

notDeepEqual

Afirmación recursiva de comparación que se busca que no sean idénticos el resultado y la expectativa.

var obj = { foo: "bar" };
notDeepEqual( obj, { foo: "bla" }, "El mismo objeto, con el mismo atributo pero el valor es distinto" );

notEqual

Comparación no estricta donde se busca que el resultado y la expectativa no sean iguales.

var numero = 2;
var texto = "dos";
notEqual(numero, texto, "El número y el texto no deben tener el mismo valor");

noStrictEqual

Una afirmación de comparación que busca que sean diferentes.

var numero = 1;
var texto = "1";
notStrictEqual(numero, texto, "La cadena de texto y el número no deben de ser idénticos. Pueden tener el mismo valor pero utilizando otro tipo de dato.");

ok

Una afirmación que recibe un valor de verdad, es válida si el primer argumento es verdadero.

var variable = true;
ok(variable, "El de la variable debe ser verdadero");

strictEqual

Una afirmación que compara que el resultado y la expectativa sean idénticos.

var valor = 1;
var otro_valor = 1;
strictEqual(valor, otro_valor, "valor y otro valor deben contener el mismo valor del mismo tipo de dato.");  

throws

Afirmación evalúa si una función envía una excepción cuando se ejecuta.

var mensaje = "Esto es una excepción.";

function excepcion() {
  throw "Esto es una excepción.";
};

throws( excepcion, mensaje, "El mensaje de la excepción debe ser igual al mensaje esperado");

Instalación y desmontaje

Para evitar que se duplique el código, podemos ejecutar código antes y / o después de que se evalúe cada prueba dentro de un módulo.

Para lograr esto, después del nombre del módulo, incluimos un objeto como parámetro. En el objeto podemos definir dos métodos.

El primer método que podemos definir es setup. Dentro de este método definimos las líneas de código que queremos ejecutar antes de que se ejecuta cada prueba del módulo donde está definido.

El segundo método que podemos definir es teardown. En este método definimos las líneas de código que queremos ejecutar después de que se ejecuta cada prueba del módulo donde está definido.

QUnit.module("Módulo", {
  setup: function (a) {
    // Código que se ejecuta antes de cada prueba del módulo
  },
  teardown: function () {
    // Código que se ejecuta después de cada prueba del módulo
  }
});

Referencia de uso

En este caso vamos a tomar como ejemplo un archivo donde se definen las cuatro operaciones aritméticas básicas – suma, resta, multiplicación y división – .

function sumar(a, b) {
  if (a === undefined) {
    a = 0;
  }
  
  if (b === undefined) {
    b = 0;
  }
  
  return a + b;
}

function restar(a, b) {
  if (a === undefined) {
    a = 0;
  }
  if (b === undefined) {
    b = 0;
  }

  return a - b;
}

function multiplicar(a, b) {
  if (a === undefined) {
    a = 0;
  }  
  if (b === undefined) {
    b = 0;
  }  
  return a * b;
}

function dividir(a, b) {
  if (a === undefined) {
    a = 1;
  }
  
  if (b === undefined) {
    b = 1;
  }
  
  return a / b;
}

Como el código ya está definido lo incluimos en el archivo.html, después de incluir qUnit y antes de incluir el archivo de las pruebas – hay que crearlo -.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Pruebas</title>
  <link rel="stylesheet" href="qunit.css" type="text/css">
  
</head>
<body>
  <div id="qunit"></div>
  <div id="qunit-fixture"></div>
  <script src="qunit.js"></script>  
  <!-- Código fuente -->
  <script src="src/funciones.js"></script>
  <!-- Pruebas -->
  <script src="test/funciones.js"></script>
</body>
</html>

Dentro de las pruebas vamos a definir dos contextos de uso – dos módulos -.
En el primer módulo vamos a evaluar la funcionalidad cuando uno de los valores no está definido.
En el segundo módulo vamos a evaluar la funcionalidad cuando ambos valores están definidos.

QUnit.module("Funciones. Cuando se tiene un valor sin definir. ");

  test( "suma dos números", function ( ) {  
    var resultado = sumar(undefined, 4);
    equal(resultado, 4, "Cuando no se define un parámetro se le debe asignar el valor cero."); 
  });
  
  test( "resta dos números", function ( ) {  
    var resultado = restar(undefined, 2);
    equal(resultado, -2, "Cuando no se define un parámetro se le debe asignar el valor cero.");      
  });

  test( "multiplica dos números", function ( ) {  
    var resultado = multiplicar(undefined, 4);
    equal(resultado, 0, "Cuando no se define un parámetro se le debe asignar el valor cero.");      
  });

  test( "divide dos números", function ( ) {  
    var resultado = dividir(undefined, 4);
    equal(resultado, 0.25, "Cuando no se define un parámetro se le debe asignar el valor uno.");      
  });

QUnit.module("Funciones. Cuando se tienen valores definidos. ");

  test( "suma dos números", function ( ) {  
    var resultado = sumar(2, 4);
    equal(resultado, 6, "Debe sumar ambos valores.");      
  });

  test( "resta dos números", function ( ) {  
    var resultado = restar(4, 2);
    equal(resultado, 2, "Debe restar ambos valores.");      
  });

  test( "multiplica dos números", function ( ) {  
    var resultado = multiplicar(2, 4);
    equal(resultado, 8, "Debe multiplicar ambos valores.");      
  });

  test( "divide dos números", function ( ) {  
    var resultado = dividir(8, 4);
    equal(resultado, 2, "Debe dividir el primer valor entre el segundo.");      
  });

En este ejemplo tanto las pruebas cómo el código están hechos. Si estuviéramos desarrollando el código o creando las pruebas para evaluar código que tengamos escrito abriríamos el archivo.html en el navegador para ir ejecutando las pruebas mientras escribimos o corregimos el código.

Visualización de qunit en el navegador.

Así es como se visualizan las pruebas en qUnit. Dentro de las opciones de visualización podemos:

  1. Esconder las pruebas que ya fueron evaluadas satisfactoriamente
  2. Revisar variables globales. qUnit hace una lista de las propiedades en el objeto window antes y después de cada prueba y revisa las diferencias. Si hay propiedades que se agregaron o eliminaron la prueba va a fallar mostrando la diferencia.
  3. “No try-catch” le dice a qUnit que se ejecute fuera de un bloque try-catch.
    Cuando la prueba lanza una excepción el código que ejecuta las pruebas se muere, incapaz de correr, pero obtienes una excepción nativa la cuál es útil para depurar en navegadores antiguos con poco soporte para la depuración como Internet Explorer 6.
  4. Si las pruebas se agruparon en módulos, qUnit permite evaluar todas las pruebas que sean parte del módulo seleccionado.

Descargar los ejemplos de referencia de qunit. Incluye el código de la clase curso – revisado en la publicación de jasmine – y una carpeta con la configuración inicial de qUnit – setup -.