Te explicamos las bases del framework de pruebas unitarias Jasmine, una herramienta que simplifica mucho las tareas de testing.
Dentro del ecosistema de JavaScript encontramos un framework con el bonito y femenino nombre de Jasmine. Se trata de una biblioteca para behavior-driven development (BDD) que permite aplicar pruebas al código JavaScript de nuestros proyectos. Para realizar las pruebas, no se necesita un DOM (Modelo de Objetos del Documento).
El propósito de Jasmine es facilitar las pruebas unitarias a los desarrolladores web. Este framework simplifica la creación de funciones para pruebas debido a su sintaxis clara y sus funciones útiles, lo que lo hace menos molesto en comparación con otros frameworks.
Características
- Posee una sintaxis muy clara y funciones que facilitan la escritura de pruebas.
- Cada test creado por el usuario es una función.
Conjunto de Funciones
La facilidad para escribir pruebas unitarias en Jasmine se debe a las siguientes funciones:
Suites
Los “suites” es un nombre que usamos para declarar a qué género o sección se va a pasar un conjunto de pruebas unitarias. "describe" es una función global que inicia cada prueba unitaria, y tiene la siguiente sintaxis:
describe("nombre de la suite", function() {
// Código de pruebas
});
Specs
Las expectativas en jasmine son afirmaciones que pueden ser ciertas o falsas dependiendo de cuál resultado el programador espere en la prueba unitaria.
"it" es una función que describe cada caso de prueba dentro de una suite: La función toma dos parámetros. El primero es una cadena de caracteres para describir un título o nombre de la prueba unitaria. Como segundo parámetro tenemos una función donde se ejecuta un bloque de código.
it("descripción del spec", function() {
// Bloque de código para el spec
});
Expectations
Son construidas con la función “expect” que toma el valor actual, ese valor está enlazado con la función matcher que toma el valor esperado. En resumen, compara el valor actual con el esperado usando matchers:
expect(valorActual).matcher(valorEsperado);
Matchers
Son métodos que realizan comparaciones booleanas entre el valor actual y el esperado. Ellos son los responsables de reportar a jasmine si la expectativa es verdadera o falsa.
Listado de matchers más comunes aunque se pueden crear matchers personalizados a la necesidad del programador.
// Verifica si ambos valores son iguales.
expect(x).toEqual(y);
// Verifica si ambos objetos son el mismo.
expect(x).toBe(y);
// Verifica si el valor cumple con el patrón establecido.
expect(x).toMatch(pattern);
// Verifica si el valor está definido.
expect(x).toBeDefined();
// Verifica si el valor es indefinido.
expect(x).toBeUndefined();
// Verifica si el valor es nulo.
expect(x).toBeNull();
// Verifica si el valor es verdaderamente "truthy" (true, no cero, no nulo, etc.).
expect(x).toBeTruthy();
// Verifica si el valor es falsamente "falsy" (false, 0, '', null, undefined, NaN).
expect(x).toBeFalsy();
// Verifica si el valor actual contiene el valor esperado (utilizado para arrays o strings).
expect(x).toContain(y);
// Verifica si el valor actual es menor que el valor esperado.
expect(x).toBeLessThan(y);
// Verifica si el valor actual es mayor que el valor esperado.
expect(x).toBeGreaterThan(y);
Organización de Specs
Jasmine nos permite agrupar muchos “specs” dentro de un “describe”, que tenga una descripción clara de lo que se está haciendo. Lo veremos en el siguiente ejemplo para dejarlo más claro.
Pero antes de ejecutar nuestro primero ejemplo debemos descargar el archivo que contiene Jasmine. Generalmente lo haremos mediante npm:
npm install --save-dev jasmine
Podemos encontrar más información en la documentación en Getting Started. En este artículo nos vamos a dedicar a escribir algunos ejemplos de utilidad.
## Ejemplo 1: Pruebas Aritméticas Básicas
describe("operaciones aritméticas", function() {
it("adición", function() {
var suma = 1 + 3;
expect(suma).toEqual(4);
});
it("resta", function() {
var resta = 3 - 1; // Corregido de 2 + 1 a 3 - 1
expect(resta).toBeLessThan(4);
});
it("multiplicación", function() {
var multiplicacion = 2 * 10;
expect(multiplicacion).toBeGreaterThan(19); // Corregido de 9 a 19 para tener sentido
});
it("división", function() {
var division = 20 / 4; // Corregido de 15 + 3 a 20 / 4
expect(division).toEqual(5);
});
});
En este ejemplo podemos observar cómo se ejecutan pruebas unitarias de las cuatro operaciones aritméticas básicas. Como se observa en el ejemplo se puede agrupar muchas pruebas en un grupo específico gracias a “specs” y “describe”.
Todo no acaba con la muestra anterior todavía jasmine tiene más sorpresas para nosotros. Se explicarán con el siguiente bloque.
Ejemplo 2: Uso de beforeEach
y afterEach
Ahora vamos a ver Organizaciones (“Setup”) y Desmontar (“Teardown”). En el ejemplo siguiente que las funciones "beforeEach" y "afterEach" permiten configurar condiciones antes y después de cada spec, respectivamente.
Con estos conceptos se pueden evitar la duplicidad de código y mantener las variables inicializadas en un solo lugar además de mantener la modularidad. Jasmine provee las funciones globales llamadas “beforeEach” y “afterEach” con las cuales nuestras pruebas unitarias serán más fáciles de realizar.
describe("operaciones aritméticas", function() {
var suma, resta, multiplicacion, division;
beforeEach(function() {
suma = 1 + 3;
resta = 3 - 1;
multiplicacion = 2 * 10;
division = 20 / 4;
});
afterEach(function() {
suma = 0; resta = 0; multiplicacion = 0; division = 0;
});
it("adición", function() {
expect(suma).toEqual(4);
});
// Otros specs...
});
Ejemplo 3: Anidación y Bloques
Otra gran ayuda que nos da jasmine es la anidación y bloques los cuales se combinan para hacer el trabajo de las pruebas unitarias algo más agradable para el programador al momento de ver cómo va ordenar su conjunto de pruebas ya que por lo general en los proyectos se codifican muchas funciones. Por ende la lista de pruebas aumenta conforme pasa el tiempo y crezcan las funcionalidades del proyecto.
La finalidad es poder crear “describe” dentro de “describe”. Esto se hace para poder darle más claridad y modularidad, la mejor manera de explicar esto es a través de nuestro último ejemplo.
describe("calculadora", function() {
describe("operaciones aritméticas", function() {
var suma, resta, multiplicacion, division;
beforeEach(function() {
suma = 1 + 3;
resta = 3
- 1;
multiplicacion = 2 * 10;
division = 20 / 4;
});
afterEach(function() {
suma = 0; resta = 0; multiplicacion = 0; division = 0;
});
it("adición", function() {
expect(suma).toEqual(4);
});
it("resta", function() {
expect(resta).toBeLessThan(4);
});
// Otros specs...
});
describe("operaciones especiales", function() {
var raizcuadrada, exponente, base;
beforeEach(function() {
raizcuadrada = Math.sqrt(16);
exponente = Math.pow(4, 3);
});
afterEach(function() {
raizcuadrada = 0; exponente = 0; base = 0;
});
it("raíz cuadrada", function() {
expect(raizcuadrada).toEqual(4);
});
it("exponente", function() {
expect(exponente).toEqual(64);
});
});
});
Con este ejemplo se observa que la anidación descrita en el párrafo anterior, algo que nos ayuda como programadores cuando realizamos pruebas unitarias en nuestros proyectos. Solo quedar animarse para implementar esta excelente herramienta en nuestro proyecto web actual o futuro.