Testing en Node con Mocha Y Chai

18-06-2020 Tiempo de lectura: 8 minutos.

¡Por fin un post algo más técnico!

Voy a comenzar avisando que esto que vamos a ver es de nivel básico para aquellos que están empezando en el desarrollo con NodeJS y comiencen con buen pie teniendo en cuenta el testing. En verdad, no deberíais tenerlo en cuenta… deberíais desarrollar a partir de vuestros test. Al final de este post dejaré algunos artículos sobre TDD, ahora vamos al turrón…

Lo primero que tenemos que hacer, (doy por hecho que tenemos lo básico instalado…NodeJS) es iniciar el proyecto con npm:

npm init

Vale, nos preguntará información sobre el proyecto y ya lo tendremos inicializado… empezamos con algo de código. Vamos a bocetar la estructura de lo que va a ser nuestro proyecto:

  • ./main.js (no necesario para el ejemplo)
  • ./services/superhero-name-composer.service.js
  • ./test/superhero-name-composer.service.spec.js

Para comenzar necesitamos las dependencias necesarias que van a ser Mocha y Chai

npm install mocha chai --save

Una vez instaladas podemos continuar… Aunque algunos (espero que seáis pocos) os resulte raro, vamos a comenzar escribiendo el test, por eso de seguir un poco el tema de TDD.

Ciclo del TDD

Empezamos a escribir el test que nos fallará puesto que no tenemos ninguna función ni nada de código implementado. Según las especificaciones del PO (Product Owner), nuestra app debe de darnos el nombre que tendríamos si fuésemos superheroes según nuestra fecha de nacimiento. ¿Qué va a hacer nuestro test? Pues probar eso mismo:

const assert = require("chai").assert;
const superheroNameComposer = require("../services/superhero-name-composer.service")

describe('when a user introduce their date of birth', ()=> {
    it('should return correct super hero name', ()=>{
        const expectedName = 'Super Calcetín Mojado'
        const resultName = superheroNameComposer.getSuperName(9,7);
        assert.equal(resultName, expectedName)
    })
})

Si lanzamos esto ahora mismo, ¡explota!, ya que no tenemos ni siquiera creado el servicio… TEST ROJO. Vamos a escribir el código mínimo para que nuestro test sea VERDE.

Creamos el fichero del servicio que estamos testeando y añadimos lo mínimo para que nuestro test pase:

exports.getSuperName = (day, month)=>{
    return "Super Calcetín Mojado"
}

Si en este punto lanzamos los test veríamos como pasan tranquilamente.

  when a user introduce their date of birth
    ✓ should return correct super hero name


  1 passing (14ms)

Esto está guay, pero el PO no quiere eso (😡)… siempre se devuelve “Super Calcetín Mojado”, así que empezamos a refactorizar el código para que tenga en cuenta los parámetros de la fecha de nacimiento (día y mes de nacimiento):

exports.getSuperName = (day, month)=>{
    return `${preName()[day-1]} ${postName()[month-1]}`
}

function preName(){
    return ["Cat","Letal","Elástico","Invisible","Capitán", "Doctor", "Sargento","Invencible", "Super","Agente","Maestro", "Robot", "Príncipe","Reina","Rey", "Fantasma", "Princesa","Mujer","Hombre","Ayudante","Terrible","Increíble", "Patético","Mr Torpe", "Mrs Torpe", "Iron", "Aprendiz","Hipster","Gurú","Hipnótico","Vigilante"]
};

function postName(){
    return ["del Mal", "Mágico", "Volador","Mutante", "Letal","Sangriento","Calcetín Mojado", "Celestial","sin Calzoncillos","Desconocido","del Javascript","de Hierro"]
};

Después de esta refactorización nuestro código estaría pasando los test y con las especificaciones que nos habían pedido, podría haber dado pasos más pequeñitos para que se viera correctamente el ciclo de TDD pero a grandes rasgos en esto consiste tanto el testing unitario en javascript, como el TDD.

¿Qué es eso de ‘describe’? ¿Y la palabra ‘it’?

Una vez que tenemos nuestro flamante compositor de super nombres terminado y testeado… entendamos un poco todas las partes de este test. Las primeras lineas son las importaciones de las dependencias que vamos a usar.

  • assert: es el tipo de aserciones que vamos a utilizar para validar las respuestas de los test. Con la librería Chai puedes elegir el tipo que mas te convenga.

  • superheroNameComposer: nuestro servicio, o el servicio que vayamos a testear.

Describe

Esta palabra que vemos en nuestro test sirve para definir bloques de pruebas, si tenemos varias pruebas, que o bien prueban lo mismo o están relacionadas, podemos engoblarlas dentro de esta función. Esto es de gran utilidad si lo combinamos junto a los hooks de Mocha.

  • before: Se ejecuta una sola vez en el bloque.
  • beforeEach: Se ejecuta antes de cada test del bloque
  • after: Se ejecuta después del último test del bloque.
  • afterEach: Se ejecuta después de cada test del bloque

Esto es útil cuando estamos probando la integración con la base de datos y queremos limpiarla después de cada test o de cada bloque, y empezar bloques nuevos de test con unos datos específicos.

It

Cada pieza de código que escribimos utilizando la palabra it dentro del bloque describe, es una prueba que vamos a realizar a nuestro código. Cada it por tanto puede probar una sola cosa pero tomando flujos distintos. Si no introduzco parámetros, si introduzco X parámetros y toda prueba que se te ocurra…

Enlaces de interés

Introduction to Test Driven Development (TDD)

TDD, una metodología para gobernarlos a todos.

TDD (Test Driven Development). Desarrollo dirigido por pruebas

Ya digo que sobre TDD podéis leer muchísimas cosas que yo aquí solo quería daros una pincelada básica.

El código lo podéis encontrar en mi repositorio de Github.

Como siempre digo… si tenéis alguna sugerencia o queréis que investigue sobre algo (siempre y cuando no se me escape de las manos, ya os digo que de reactores nucleares no tengo ni idea) solo tenéis que decírmelo a través de Twitter