Qué es Mocha y cómo usar este Framework Javascript para desarrollo de pruebas unitarias. Conceptos esenciales de Mocha con ejemplos de código útiles para entenderlos.
Mocha puede definirse como un framework de pruebas rico en características, implementable tanto en Node.js como en navegadores. Este framework ejecuta las pruebas en serie, lo que permite generar reportes flexibles y precisos. Así, el código que ha pasado las pruebas resulta óptimo para su uso en producción. Sin embargo, la esencia de Mocha puede resumirse en tres palabras: "simple", "flexible" y "divertido".
Características o Atributos
- Soporte para diferentes navegadores
- Reportes de cobertura de código
- Uso de cualquier librería de afirmaciones
- Javascript api para ejecutar pruebas.
- Soporte de Debugger para nodejs
Son unas de las muchas características del sistema. En realidad existen más destacables, sin contar con que Mocha cada día crece y gana adeptos en el campo de pruebas unitarias.
Instalación
La instalación se hará de la manera más sencilla, por medio de npm, el gestor de paquetes de nodejs.
Para poder realizar esta operación necesitamos tener instalado nodejs. Tiene soporte para muchos sistemas operativos. Puedes encontrar información en el Manual de NodeJS.
Para instalarlo tenemos dos opciones. La primera es hacerlo de manera global en nuestro sistema:
$ npm install --global mocha
Sin embargo es todavía más adecuado instalarlo como dependencia de desarrollo en los proyectos donde lo necesitemos.
$ npm install --save-dev mocha
Una vez instalado el paquete ya se pueden hacer las pruebas unitarias Antes de ver ejemplos vamos a abordar conceptos relevantes para entender esta suite de pruebas. Luego veremos sus respectivos ejemplos para entenderlos de una manera práctica.
Assertions o Afirmaciones
Mocha te permite utilizar cualquier librería de "Assertions" o afirmaciones, como por ejemplo should.js, expect.js, chai y better-assert. Esto la hace más flexible y adaptable a los gustos de los programadores que tengan experiencia en una librería en particular.
Por medio de la línea de comandos ejecutamos las siguiente sentencia.
mkdir PU_Mocha
Luego puedes crear ya los ejemplos de pruebas en esa carpeta con tu editor favorito. Puedes crear un archivo llamado “prueba.js”.
Ejemplo de código de pruebas con Mocha
En este ejemplo vamos a probar que la función substring
de JavaScript. Usamos Mocha como framework de pruebas y assert para las afirmaciones.
var assert = require("assert");
describe("Cadenas", function() {
describe("subcadenas", function() {
it('debería retornar una subcadena', function() {
// Asegurarse de que el substring extraído sea "Bello"
assert.equal("Bello", "Panama es Bello".substring(10, 15));
});
});
});
Para ejecutar este código debemos lanzar el comando siguiente:
mocha prueba.js
Una vez ejecutado se presenta una salida como en la siguiente imagen.
Ahora vamos a ver algunas descripciones más detalladas del código anterior.
- La primera línea importa el módulo “assert” de Node.js, que proporciona funciones para realizar verificaciones o afirmaciones en las pruebas unitarias.
- La segunda línea define una suite de pruebas llamada “Cadenas”, indicando que se agruparán aquí pruebas relacionadas con manipulación y características de cadenas de texto. La tercera línea define una sub-suite dentro de "Cadenas" llamada “subcadenas”, dedicada exclusivamente a pruebas relacionadas con la extracción de subcadenas.
- La cuarta línea especifica el título de un caso de prueba concreto, donde se evaluará si una subcadena específica es extraída correctamente.
- La quinta línea utiliza una afirmación para comprobar que la función substring de JavaScript extrae correctamente "Bello" de la cadena completa "Panama es Bello".
Algunas explicaciones detalladas sobre el módulo assert
assert
es un módulo en Node.js que proporciona un conjunto de funciones de afirmación (assertion functions) utilizadas para verificar que ciertas condiciones sean verdaderas. Es utilizado principalmente para escribir pruebas unitarias, y su objetivo es simplificar el proceso de codificación de estas pruebas al ofrecer métodos sencillos que prueban la veracidad de una afirmación.
Cuando se escribe una prueba utilizando assert
, estás básicamente diciendo que esperas que algo sea verdadero en un punto específico del código. Si la afirmación es verdadera (la condición evaluada devuelve true
), la prueba pasa y no sucede nada más. Pero si la afirmación es falsa (la condición devuelve false
), assert
lanzará un error (AssertionError
), indicando que algo en el código no funcionó como se esperaba.
Funciones Comunes de assert
El módulo assert
viene con varias funciones que se pueden utilizar para diferentes tipos de pruebas de afirmaciones:
assert(value, message)
: Prueba sivalue
es verdadero. Si no lo es, se lanza un error con elmessage
proporcionado.assert.ok(value, message)
: Es un alias deassert(value, message)
.assert.equal(actual, expected, message)
: Prueba la igualdad entreactual
yexpected
usando el operador de igualdad (==
).assert.strictEqual(actual, expected, message)
: Prueba la igualdad estricta entreactual
yexpected
usando el operador de igualdad estricta (===
).assert.deepEqual(actual, expected, message)
: Prueba la igualdad profunda entreactual
yexpected
. Es útil para comparar objetos y arrays.assert.notEqual(actual, expected, message)
: Prueba queactual
yexpected
no son iguales usando!=
.assert.notStrictEqual(actual, expected, message)
: Prueba queactual
yexpected
no son estrictamente iguales usando!==
.assert.notDeepEqual(actual, expected, message)
: Prueba queactual
yexpected
no son profundamente iguales.
Uso de assert
en Pruebas Unitarias
Aquí hay un ejemplo simple de cómo se podría usar assert
en un escenario de prueba unitaria:
const assert = require('assert');
function sum(a, b) {
return a + b;
}
describe('Test Suite for Sum Function', function() {
it('should return 5 when adding 2 and 3', function() {
assert.strictEqual(sum(2, 3), 5, "The sum of 2 and 3 should be 5");
});
it('should return 10 when adding 7 and 3', function() {
assert.strictEqual(sum(7, 3), 10, "The sum of 7 and 3 should be 10");
});
});
En este ejemplo, assert.strictEqual
se usa para asegurar que la función sum
devuelve el resultado correcto para las entradas dadas. Si alguno de estos tests falla, Mocha reportará el error usando el mensaje proporcionado y el test será marcado como fallido.
Ejemplo de Mocha usando la biblioteca de assertions should.js
Para el siguiente ejemplo, utilizaremos la biblioteca de afirmaciones should.js
, que es muy conocida y se puede instalar mediante el siguiente comando:
npm install should
El código del ejemplo es el siguiente:
var should = require("should"); // Requiere la biblioteca should.js para usar en las pruebas
describe("Cadenas", function() {
describe("subcadenas", function() {
it('usando la librería should', function() {
'Panama es Bello'.substring(10, 15).should.equal('Bello'); // Prueba que la subcadena extraída es igual a 'Bello'
});
});
});
Explicación detallada del código
- Primera línea: Importa la biblioteca
should
, que utilizaremos para realizar las afirmaciones en nuestras pruebas unitarias. - Quinta línea: Aquí se ejecuta la prueba unitaria. Se verifica que la subcadena extraída de "Panama es Bello" sea igual a "Bello", utilizando para ello el método
.should.equal()
proporcionado porshould.js
. - General: Este ejemplo demuestra la facilidad de uso de la biblioteca
should.js
para realizar afirmaciones en pruebas unitarias de manera concisa y legible.
Organizaciones en Mocha
Las organizaciones o configuraciones preliminares nos ayudan a mantener nuestras pruebas unitarias organizadas y claras mediante la inicialización de variables y la segmentación del código. Esto no solo mejora la legibilidad, sino que también facilita la comprensión y el mantenimiento del código por otros programadores.
Veamos un ejemplo:
describe('calculadora', function() {
var a, b;
beforeEach(function() {
a = 4;
b = 2;
});
describe('operaciones básicas', function() {
it('suma', function() {
assert.equal(a + b, 6);
});
it('resta', function() {
assert.equal(a - b, 2);
});
});
});
El ejemplo demuestra cómo las variables a
y b
son inicializadas con sus valores respectivos antes de cada prueba unitaria gracias a la función beforeEach
. Esto elimina la necesidad de repetir la configuración de estas variables en cada caso de prueba, simplificando el proceso y asegurando que el estado inicial es consistente para todas las pruebas en este bloque.
Qué son las Pruebas Exclusivas de Mocha
La característica de exclusividad permite enfocar nuestras pruebas unitarias en un módulo o prueba específica dentro de nuestro código JavaScript. Esta funcionalidad es útil para centrarse detenidamente en aspectos particulares durante la fase de prueba. A continuación, se presentan dos ejemplos que ilustran esta característica.
Ahora tenemos un ejemplo para entenderlo mejor.
describe('Calculadora', function() {
var a, b;
beforeEach(function() {
a = 4;
b = 2;
});
describe('operaciones básicas 1', function() {
it('suma', function() {
assert.equal(a + b, 6);
});
it('resta', function() {
assert.equal(a - b, 2);
});
});
describe.only('operaciones básicas 2', function() {
it('multiplicación', function() {
assert.equal(a * b, 8);
});
it('división', function() {
assert.equal(a / b, 2);
});
});
});
La palabra reservada only
es utilizada aquí para limitar la ejecución únicamente al módulo denominado “operaciones básicas 2”. Esto significa que, de todas las pruebas definidas, solo se ejecutarán las dos pertenecientes a este módulo específico.
Sobre pruebas exclusivas en Mocha queremos ver todavía un segundo código.
describe('calculadora', function() {
describe('operaciones especiales', function() {
it('raíz cuadrada', function() {
assert.equal(Math.sqrt(16), 4);
});
it.only('exponentes', function() {
assert.equal(Math.pow(4, 2), 16);
});
});
});
Dentro del módulo denominado “operaciones especiales”, únicamente se ejecuta la prueba unitaria correspondiente a “exponentes” debido a la utilización de la palabra reservada “only”. Esta funcionalidad es una herramienta muy útil dentro de este framework.
Pruebas no Exclusivas en Mocha
Ahora entendamos el concept de pruebas no exclusivas que nos permiten ignorar módulos o pruebas unitarias que no son prioritarias al momento de ejecutar las pruebas.
Los siguientes ejemplos ilustran lo descrito en la teoría.
describe('Gestión de cadenas', function() {
describe.skip('subcadenas', function() {
it('prueba de subcadena', function() {
assert.equal("Bella", "Panama es Bella".substring(10, 15));
});
});
describe('contador', function() {
it('cantidad de caracteres', function() {
assert.equal("Panama es Bella".length, 15);
});
});
});
Al ejecutar este código, se muestra un mensaje indicando que existen pruebas unitarias pendientes, gracias a la palabra reservada “skip” en el módulo llamado “subcadenas”. Esto significa que las pruebas dentro de “subcadenas” no se ejecutarán.
Veamos un segundo ejemplo de pruebas no exclusivas de Mocha.
describe('Gestión de cadenas', function() {
describe('subcadenas', function() {
it('prueba de subcadena', function() {
assert.equal("Bella", "Panama es Bella".substring(10, 15));
});
});
describe('contador', function() {
it.skip('cantidad de caracteres', function() {
assert.equal("Panama es Bella".length, 15);
});
});
});
En este ejemplo, siempre quedará una prueba unitaria pendiente, la cual es la llamada “cantidad de caracteres”. Esta prueba no se ejecutará debido a la palabra reservada “skip”.
Conclusión
A lo largo de este artículo, hemos explorado diversas características de Mocha, desde la instalación y las primeras pruebas con librerías de assertions, hasta la ejecución de pruebas exclusivas y no exclusivas o la organización eficiente de tests mediante descripciones y configuraciones preliminares. Hemos visto cómo Mocha facilita una estructura clara y mantenible, que resulta accesible tanto para nuevos programadores como para profesionales experimentados.
Mocha no solo demuestra ser una herramienta versátil para proyectos personales, sino que también se adapta robustamente a las exigencias de entornos de desarrollo profesional. Su capacidad para integrarse con diversas bibliotecas de aserciones y su soporte para pruebas asíncronas son solo algunas de las características que lo hacen atractivo para una amplia gama de aplicaciones de software.
Personalmente, considero que Mocha tiene un prometedor futuro en el ámbito de las pruebas de software. La simplicidad en la definición de pruebas, combinada con la potencia de sus herramientas, prepara el terreno para innovaciones futuras que seguirán enriqueciendo este ya impresionante framework.
Invito a todos a incorporar Mocha en sus proyectos y experimentar por sí mismos la eficacia de sus funcionalidades. Felices pruebas, o como diríamos en inglés, “Happy Testing!”