Probando el c贸digo de Node.js con Mocha y Chai

    Escribir pruebas unitarias es una de esas cosas que mucha gente se olvida de hacer o simplemente evita por completo, pero cuando las tienes son salvavidas.

    Desarrollo impulsado por pruebas, lo que significa que escribe sus pruebas antes que su c贸digo, es un gran objetivo por el que luchar, pero requiere disciplina y planificaci贸n cuando est谩 programando. Para que todo este proceso sea mucho m谩s f谩cil, necesita marcos de prueba y afirmaci贸n potentes y f谩ciles de usar, que es exactamente lo que Moca y Chai son.

    En este art铆culo, te presentar茅 estas dos bibliotecas y te mostrar茅 c贸mo usarlas juntas para crear r谩pidamente pruebas de unidades funcionales y legibles.

    Chai

    Chai es una biblioteca de aserciones que proporciona tanto BDD y TDD estilos de programaci贸n para probar su c贸digo en cualquier marco de prueba.

    A lo largo de este art铆culo, nos centraremos en el estilo BDD usando Chai expect interfaz.

    expect utiliza una API de lenguaje m谩s natural para escribir sus afirmaciones, lo que har谩 que sus pruebas sean m谩s f谩ciles de escribir y mejorar m谩s adelante en el futuro. Esto se hace encadenando getters para crear y ejecutar la aserci贸n, lo que facilita la traducci贸n de los requisitos al c贸digo:

    var user = {name: 'Scott'};
    
    // Requirement: The object 'user' should have the property 'name'
    
    expect(user).to.have.property('name');
    

    Algunos ejemplos m谩s de estos captadores son:

    • to
    • be
    • is
    • and
    • has
    • have

    Muchos de estos captadores se pueden encadenar y utilizar con m茅todos de aserci贸n como true, ok, existy empty para crear algunas afirmaciones complejas en una sola l铆nea. Algunos ejemplos:

    "use strict";
    
    var expect = require('chai').expect;
    
    // Simple assertions
    expect({}).to.exist;
    expect(26).to.equal(26);
    expect(false).to.be.false;
    expect('hello').to.be.string;
    
    // Modifiers ('not')
    expect([1, 2, 3]).to.not.be.empty;
    
    // Complex chains
    expect([1, 2, 3]).to.have.length.of.at.least(3);
    

    Se puede encontrar una lista completa de los m茅todos disponibles aqu铆.

    Tambi茅n puede consultar la lista de plugins para Chai. Esto hace que sea mucho m谩s f谩cil probar funciones m谩s complejas.

    Tomar chai-http por ejemplo, que es un plugin que le ayuda a probar las rutas del servidor.

    "use strict";
    
    var chai = require('chai');
    var chaiHttp = require('chai-http');
    
    chai.use(chaiHttp);
    
    chai.request(app)
        .put('/api/auth')
        .send({username: '[email聽protected]', passsword: 'abc123'})
        .end(function(err, res) {
            expect(err).to.be.null;
            expect(res).to.have.status(200);
        });
    

    Moca

    Mocha es un marco de prueba para Node.js que le brinda la flexibilidad de ejecutar c贸digo asincr贸nico (o s铆ncrono) en serie. Cualquier excepci贸n no detectada se muestra junto con el caso de prueba en el que se lanz贸, lo que facilita la identificaci贸n exacta de qu茅 fall贸 y por qu茅.

    Para usar Mocha, le sugiero que lo instale globalmente con npm:

    $ npm install mocha -g
    

    Querr谩 que sea una instalaci贸n global ya que mocha El comando se utiliza para ejecutar las pruebas del proyecto en su directorio local.

    La creaci贸n de casos de prueba es f谩cil con el describe() m茅todo. describe() se utiliza para estructurar sus pruebas agrupando otros describe() llamadas y it() m茅todos juntos, que es donde se encuentran las pruebas reales. Esto probablemente se describe mejor con un ejemplo:

    "use strict";
    
    var expect = require('chai').expect;
    
    describe('Math', function() {
        describe('#abs()', function() {
            it('should return positive value of given negative number', function() {
                expect(Math.abs(-5)).to.be.equal(5);
            });
        });
    });
    

    Tenga en cuenta que con las pruebas de Mocha no es necesario require() cualquiera de los m茅todos Mocha. Estos m茅todos se proporcionan globalmente cuando se ejecutan con el mocha mando.

    Para ejecutar estas pruebas, guarde su archivo y use el mocha mando:

    $ mocha .
    
    
      Math
        #abs()
          鉁 should return positive value of given number 
    
    
      1 passing (9ms)
    

    El resultado es un desglose de las pruebas que se ejecutaron y sus resultados. Note como el anidado describe() las llamadas se transfieren a la salida de resultados. Es 煤til tener todas las pruebas para un m茅todo o caracter铆stica determinada anidadas juntas.

    Estos m茅todos son la base del marco de prueba de Mocha. 脷salos para componer y organizar tus pruebas como quieras. Veremos un ejemplo de esto en la siguiente secci贸n.

    Pruebas de escritura

    La forma recomendada de organizar sus pruebas dentro de su proyecto es ponerlas todas en su propio /test directorio. De forma predeterminada, Mocha comprueba las pruebas unitarias utilizando los globs ./test/*.js y ./test/*.coffee. A partir de ah铆, cargar谩 y ejecutar谩 cualquier archivo que llame al describe() m茅todo.

    Personalmente, me gusta usar el sufijo .test.js para los archivos de origen que realmente contienen pruebas de Mocha. Entonces, una estructura de directorio de ejemplo podr铆a verse as铆:

    鈹溾攢鈹 package.json
    鈹溾攢鈹 lib
    鈹   鈹溾攢鈹 db.js
    鈹   鈹溾攢鈹 models.js
    鈹   鈹斺攢鈹 util.js
    鈹斺攢鈹 test
        鈹溾攢鈹 db.test.js
        鈹溾攢鈹 models.test.js
        鈹溾攢鈹 util.test.js
        鈹斺攢鈹 util.js
    

    util.js no contendr铆a ninguna prueba unitaria real, solo funciones de utilidad para ayudar con las pruebas.

    Puedes usar cualquier estructura que tenga sentido para ti (que es lo bueno de Mocha), pero esto me ha funcionado bien en el pasado.

    Cuando se trata de redactar las pruebas, es 煤til organizarlas utilizando el describe() m茅todos. Puede organizarlos por caracter铆stica, funci贸n, archivo u otra cosa.

    Ampliando nuestro ejemplo de la secci贸n anterior, elegiremos organizar las pruebas por funci贸n, lo que da como resultado algo que se ve as铆:

    "use strict";
    
    var expect = require('chai').expect;
    
    describe('Math', function() {
        describe('#abs()', function() {
            it('should return positive value of given negative number', function() {
                expect(Math.abs(-5)).to.be.equal(5);
            });
    
            it('should return positive value of given positive number', function() {
                expect(Math.abs(3)).to.be.equal(3);
            });
    
            it('should return 0 given 0', function() {
                expect(Math.abs(0)).to.be.equal(0);
            });
        });
    });
    

    Ejecutar las pruebas le dar铆a el resultado:

    $ mocha .
    
    
      Math
        #abs()
          鉁 should return positive value of given negative number 
          鉁 should return positive value of given positive number 
          鉁 should return 0 given 0 
    
    
      3 passing (11ms)
    

    Ampliando a煤n m谩s (lo prometo, este es el 煤ltimo que mostrar茅), es posible que incluso tenga pruebas para varios m茅todos en un solo archivo. En este caso, los m茅todos se agrupan por Math objeto:

    "use strict";
    
    var expect = require('chai').expect;
    
    describe('Math', function() {
        describe('#abs()', function() {
            it('should return positive value of given negative number', function() {
                expect(Math.abs(-5)).to.be.equal(5);
            });
    
            it('should return positive value of given positive number', function() {
                expect(Math.abs(3)).to.be.equal(3);
            });
    
            it('should return 0 given 0', function() {
                expect(Math.abs(0)).to.be.equal(0);
            });
        });
    
        describe('#sqrt()', function() {
            it('should return the square root of a given positive number', function() {
                expect(Math.sqrt(25)).to.be.equal(5);
            });
    
            it('should return NaN for a given negative number', function() {
                expect(Math.sqrt(-9)).to.be.NaN;
            });
    
            it('should return 0 given 0', function() {
                expect(Math.sqrt(0)).to.be.equal(0);
            });
        });
    });
    

    Salida:

    $ mocha .
    
    
      Math
        #abs()
          鉁 should return positive value of given negative number 
          鉁 should return positive value of given positive number 
          鉁 should return 0 given 0 
        #sqrt()
          鉁 should return the square root of a given positive number 
          鉁 should return NaN for a given negative number 
          鉁 should return 0 given 0 
    
    
      6 passing (10ms)
    

    Bien, entiendes la idea.

    Es cierto que la mayor铆a de las pruebas unitarias no son tan simples. Muchas veces probablemente necesitar谩 otros recursos para realizar sus pruebas, como una base de datos o alg煤n otro recurso externo. Para configurar esto, podemos usar uno o m谩s de los siguientes Gancho de moca m茅todos:

    • before(): Se ejecuta antes de todas las pruebas en el bloque dado
    • beforeEach(): Se ejecuta antes de cada prueba en el bloque dado
    • after(): Se ejecuta despu茅s de todas las pruebas en el bloque dado
    • afterEach(): Se ejecuta despu茅s de cada prueba en el bloque dado

    Estos ganchos son el lugar perfecto para realizar los trabajos de instalaci贸n y desmontaje necesarios para sus pruebas. Como ya mencion茅, uno de los casos de uso comunes es establecer una conexi贸n a su base de datos antes de ejecutar las pruebas, que se muestra en el siguiente ejemplo:

    "use strict";
    
    var expect = require('chai').expect;
    var Camo = require('camo');
    var User = require('../models').User;
    
    describe('Users', function() {
    
        var database = null;
    
        before(function(done) {
            Camo.connect('mongodb://localhost/app_test').then(function(db) {
                database = db;
                return database.dropDatabase();
            }).then(function() {}).then(done, done);
        });
    
        afterEach(function(done) {
            database.dropDatabase().then(function() {}).then(done, done);
        });
    
        describe('#save()', function() {
            it('should save User data to database', function(done) {
                // Use your database here...
            });
        });
    
        describe('#load()', function() {
            it('should load User data from database', function(done) {
                // Use your database here...
            });
        });
    });
    

    Antes de ejecutar cualquiera de las pruebas, la funci贸n enviada a nuestro before() se ejecuta el m茅todo (y solo se ejecuta una vez durante las pruebas), lo que establece una conexi贸n a la base de datos. Una vez hecho esto, se ejecutan nuestras suites de prueba.

    Dado que no queremos que los datos de un conjunto de pruebas afecten a nuestras otras pruebas, necesitamos borrar los datos de nuestra base de datos despu茅s de ejecutar cada conjunto. Esto es lo que afterEach() es para. Usamos este enlace para borrar todos los datos de la base de datos despu茅s de que se ejecuta cada caso de prueba, de modo que podamos comenzar desde una pizarra limpia para las pr贸ximas pruebas.

    Ejecuci贸n de pruebas

    Para la mayor铆a de los casos, esta parte es bastante simple. Suponiendo que ya haya instalado Mocha y haya navegado al directorio del proyecto, la mayor铆a de los proyectos solo necesitan usar el mocha comando sin argumentos para ejecutar sus pruebas.

    $ mocha
    
    
      Math
        #abs()
          鉁 should return positive value of given negative number 
          鉁 should return positive value of given positive number 
          鉁 should return 0 given 0 
        #sqrt()
          鉁 should return the square root of a given positive number 
          鉁 should return NaN for a given negative number 
          鉁 should return 0 given 0 
    
    
      6 passing (10ms)
    

    Esto es ligeramente diferente a nuestros ejemplos anteriores, ya que no necesit谩bamos decirle a Mocha d贸nde estaban ubicadas nuestras pruebas. En este ejemplo, el c贸digo de prueba est谩 en la ubicaci贸n esperada de /test.

    Sin embargo, existen algunas opciones 煤tiles que puede utilizar al realizar pruebas. Si algunas de sus pruebas fallan, por ejemplo, probablemente no desee ejecutar toda la suite cada vez que realice un cambio. Para algunos proyectos, el conjunto de pruebas completo puede tardar unos minutos en completarse. Eso es mucho tiempo perdido si realmente solo necesita ejecutar una prueba.

    Para casos como este, debe decirle a Mocha qu茅 pruebas debe ejecutar. Esto se puede hacer usando el -g <pattern> o -f <sub-string> opciones.

    Nuevamente, usando los ejemplos de arriba, podemos usar el -g opci贸n de ejecutar solo nuestro #sqrt() pruebas:

    $ mocha -g sqrt
    
    
      Math
        #sqrt()
          鉁 should return the square root of a given positive number 
          鉁 should return NaN for a given negative number 
          鉁 should return 0 given 0 
    
    
      3 passing (10ms)
    

    Note que el #abs() Las pruebas no se incluyeron en esta ejecuci贸n. Si planifica en consecuencia con los nombres de sus pruebas, esta opci贸n se puede utilizar para ejecutar solo secciones espec铆ficas de sus pruebas.

    Sin embargo, estas no son las 煤nicas opciones 煤tiles. Aqu铆 hay algunas opciones m谩s para Mocha que es posible que desee consultar:

    • --invert: Invierte -g y -f partidos
    • --recursive: Incluir subdirectorios
    • --harmony: Habilita todas las funciones de armon铆a en Node

    Puede consultar la lista completa de opciones utilizando el mocha -h comando, o en esta p谩gina.

    D贸nde aprender m谩s

    Hay mucho m谩s sobre este tema de lo que podemos cubrir en una breve publicaci贸n de blog, por lo que si desea obtener m谩s informaci贸n, le recomiendo que consulte los siguientes recursos:

    En lugar de simplemente leer la documentaci贸n, tambi茅n puede probar un curso sobre este tema, al que vincul茅 a continuaci贸n. El instructor detalla c贸mo configurar el uso de Mocha, Chai y Sinon para probar el c贸digo Node.js, as铆 como videos detallados para cada tema.

    Aprenda las pruebas unitarias de JavaScript con Mocha, Chai y Sinon

    Es un gran plugin para este art铆culo y tambi茅n es m谩s f谩cil de digerir que los sitios web de documentaci贸n gracias a su formato de video.

    Conclusi贸n

    Tenga en cuenta que tanto Mocha como Chai se pueden usar para probar casi cualquier tipo de proyecto de Node, ya sea una biblioteca, una herramienta de l铆nea de comandos o incluso un sitio web. Utilizando las diversas opciones y plugins disponibles para usted, deber铆a poder satisfacer sus necesidades de prueba con bastante facilidad. Cada una de estas bibliotecas es muy 煤til para validar su c贸digo y debe usarse en casi todos sus proyectos de Node.

    Con suerte, esto ha servido como una introducci贸n 煤til a Mocha y Chai. Hay mucho m谩s que aprender de lo que he presentado aqu铆, as铆 que aseg煤rese de consultar los documentos para obtener m谩s informaci贸n.

    驴Tiene alg煤n consejo 煤til para escribir pruebas de Mocha / Chai? 隆H谩znoslo saber en los comentarios!

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *