Uso de Mocks para pruebas en JavaScript con Sinon.js

U

Introducción

Los “simulacros” de prueba son objetos que reemplazan a los objetos reales mientras simulan sus funciones. Un simulacro también tiene expectativas sobre cómo se utilizarán las funciones que se están probando.

En algunos casos de prueba unitaria, es posible que deseemos combinar la funcionalidad de espías, para observar el comportamiento de un método bajo una llamada, y el de los apéndices, para reemplazar la funcionalidad de un método, para asegurarnos de que no hacemos una llamada de función real pero que aún podemos monitorear el comportamiento de nuestra función objetivo en consecuencia. En tal caso, podemos usar simulacros.

En este artículo, buscaremos comprender qué son los simulacros y cómo usarlos en pruebas unitarias. Luego tendremos experiencia práctica con Sinon.js para simular una solicitud HTTP.

Este artículo es el tercero de nuestra serie sobre técnicas de prueba unitaria con Sinon.js. Le recomendamos que lea también nuestros artículos anteriores sobre este tema:

  • Uso de stubs para pruebas en JavaScript con Sinon.js
  • Uso de espías para realizar pruebas en JavaScript con Sinon.js
  • Uso de simulacros para pruebas en JavaScript con Sinon.js (está aquí)

¿Qué son los simulacros?

Los simulacros combinan la funcionalidad tanto de espías como de códigos auxiliares, lo que significa que reemplazan la función objetivo pero al mismo tiempo nos brindan la capacidad de observar cómo se llamó a la función.

Además, los simulacros tienen afirmaciones incorporadas llamadas expectativas. Usted define las expectativas de cómo se utilizará su función simulada por adelantado. Si su simulacro no satisfizo sus expectativas, su prueba fallará.

Por ejemplo, consideremos una función que se comunica con una base de datos para guardar los detalles de un contacto. Con un simulacro, en lugar de una base de datos real, nuestra función golpeará un objeto de base de datos falso. Podemos determinar qué tipo de respuesta dará. También indicaremos cuántas veces se debe llamar a la base de datos y los argumentos con los que se debe llamar.

Finalmente, como parte de la prueba, verificamos que nuestra simulación de base de datos fue llamada la cantidad exacta de veces que esperábamos. También verificamos que se haya llamado solo con los argumentos que nuestra función supuestamente debe proporcionar.

Habiendo visto lo que son las burlas, veamos ahora situaciones en las que podemos emplearlas.

¿Por qué utilizar Mocks?

Los simulacros son útiles para validar cómo se usa una dependencia externa dentro de una función. Utilice simulacros cuando esté interesado en:

  • Confirmando que su dependencia externa se usa en absoluto
  • Verificando que su dependencia externa se use correctamente
  • Asegurarse de que su función pueda manejar diferentes respuestas de dependencias externas.

Imagine que está probando una función que habla con una API de terceros para obtener algunos datos del usuario. Para realizar solicitudes a la API externa, primero deberá realizar algunas llamadas para autenticarse. Ya se está volviendo un inconveniente utilizar la API real en las pruebas. Además, es posible que no siempre tenga una conexión a Internet para acceder a la API mientras realiza sus pruebas.

Con un simulacro, devolveremos respuestas falsas. Ahora podemos probar rápidamente que nuestra función se comporta correctamente cuando se le dan datos falsos en un formato particular. También sabremos que nuestra función realizó solicitudes a la API con los parámetros correctos.

Veamos ahora cómo podemos usar Sinon.js para crear simulaciones.

Usando Sinon.js para crear un simulacro

Usaremos Sinon.js para simular una respuesta de una API JSON que recupera una lista de fotos en un álbum. Además de Sinon.js, usaremos Moca y Chai para configurar y ejecutar las pruebas. Puede leer nuestra guía nuestra guía para conocer más sobre ellos antes de continuar.

Preparar

Crea un directorio llamado SinonMock y muévete a él:

$ mkdir SinonMock
$ cd SinonMock

Luego usaremos NPM para inicializar un proyecto para rastrear los archivos del proyecto que creamos:

$ npm init -y

A continuación, instalaremos Mocha y Chai como dependencias de prueba para ejecutar nuestras pruebas, junto con Sinon.js:

$ npm i mocha chai sinon --save-dev

Una vez completada nuestra configuración, simulemos una solicitud HTTP.

Burlarse de una llamada HTTP con Sinon.js

En nuestro artículo anterior sobre espías de prueba, espiamos una solicitud HTTP a la API del álbum de fotos. Continuaremos con ese ejemplo para este artículo.

Cree un archivo en la raíz del SinonMock directorio y llamarlo index.js:

$ touch index.js

En el archivo creado, ingrese el siguiente código:

const request = require('request');

module.exports = {
    getAlbumById: async function(id) {
        const requestUrl = `https://jsonplaceholder.typicode.com/albums/${id}/photos?_limit=3`;
        return new Promise((resolve, reject) => {
            request.get(requestUrl, (err, res, body) => {
                if (err) {
                    return reject(err);
                }
                resolve(JSON.parse(body));
            });
        });
    }
};

Recordar, getAlbumById() es una función que llama a una API JSON que devuelve una lista de fotos. Proporcionamos un ID de álbum como argumento de función. Anteriormente hemos explorado el secuestro y el espionaje de request.get() método.

Ahora, nos burlaremos del request objeto y compruebe si el get() se llama al método una vez, según sea necesario, y verifique si recibió los argumentos correctos. Luego verificaremos que nuestra función tenga las propiedades correctas según lo que se devolvió de nuestro simulacro.

Cree otro archivo en la raíz del SinonMock directorio y llamarlo index.test.js:

$ touch index.test.js

Abre el index.test.js archivo con un editor e ingrese el siguiente código:

const expect = require('chai').expect;
const request = require('request');
const sinon = require('sinon');
const index = require('./index');

describe('with mock: getPhotosByAlbumId', () => {
    it('should getPhotosByAlbumId', (done) => {
        let requestMock = sinon.mock(request);
        const myPhotos = [{
            "albumId": 1,
            "id": 1,
            "title": "accusamus beatae ad facilis cum similique qui sunt",
            "url": "https://via.placeholder.com/600/92c952",
            "thumbnailUrl": "https://via.placeholder.com/150/92c952"
        },
        {
            "albumId": 1,
            "id": 2,
            "title": "reprehenderit est deserunt velit ipsam",
            "url": "https://via.placeholder.com/600/771796",
            "thumbnailUrl": "https://via.placeholder.com/150/771796"
        },
        {
            "albumId": 1,
            "id": 3,
            "title": "officia porro iure quia iusto qui ipsa ut modi",
            "url": "https://via.placeholder.com/600/24f355",
            "thumbnailUrl": "https://via.placeholder.com/150/24f355"
        }];

        requestMock.expects("get")
            .once()
            .withArgs('https://jsonplaceholder.typicode.com/albums/2/photos?_limit=3')
            .yields(null, null, JSON.stringify(myPhotos));

        index.getAlbumById(2).then((photos) => {
            expect(photos.length).to.equal(3);
            photos.forEach((photo) => {
                expect(photo).to.have.property('id');
                expect(photo).to.have.property('title');
                expect(photo).to.have.property('url');
            });

            requestMock.verify();
            requestMock.restore();
            done();
        });
    });
});

En nuestro caso de prueba anterior, primero creamos una simulación del request objeto usando sinon.mock() y nombrarlo requestMock. los requestMock El objeto tiene las funciones del request objeto pero las funciones no hacen nada por defecto.

Después de proporcionar algunos datos fotográficos fijos, anulamos el original get() método del objeto de solicitud mediante el uso de API simuladas de Sinon.js expect() método.

los expect() El método toma un solo argumento, que es el método del objeto simulado que anticipamos que se usará.

los once() El método afirma que nuestra expectativa se llama una vez. En este caso el get() El método del objeto de solicitud se llamará exactamente una vez.

los withArgs() El método afirma que esperamos el get() método que se llamará con la matriz de argumentos que le proporcionamos. En nuestro caso la URL de la API.

los yields() El método coloca datos en la devolución de llamada que acepta nuestro objeto simulado. En este caso, nuestro error y respuesta son ambos null pero nuestro cuerpo tiene una respuesta JSON.

Después de esta configuración, llamamos a nuestro getAlbumById() y compruebe si las fotos volvieron a tener las propiedades correctas.

Observe la verify() llamada del requestMock objetar para confirmar que se cumplieron nuestras expectativas. Si las expectativas fallan, la prueba arrojará una excepción. Luego llamamos al restore() método para descartar el simulacro creado por nuestra prueba y restaurar el objeto de solicitud original.

Cuando ejecute esta prueba, debería obtener el siguiente resultado:

$ mocha index.test.js

with mock: getPhotosByAlbumId
    ✓ should getPhotosByAlbumId


  1 passing (13ms)

✨  Done in 0.72s.

Para confirmar el comportamiento de nuestro simulacro, veamos si las expectativas fallan si cambiamos la URL con la que nos comunicamos. En tus index.js archivo, cambio:

const requestUrl = `https://jsonplaceholder.typicode.com/albums/${id}/photos?_limit=3`;

A:

const requestUrl = `https://example.com`;

Ahora ejecuta las pruebas una vez más:

$ mocha index.test.js

Desde que cambiamos la entrada al get() , el argumento de la URL ya no coincide con lo que está en nuestra prueba. Obtendremos este resultado cuando ejecutemos la prueba:

> mocha index.test.js



  with mock: getPhotosByAlbumId
(node:85434) UnhandledPromiseRejectionWarning: ExpectationError: Unexpected call: get(https://example.com, function () {})
    Expected get(https://jsonplaceholder.typicode.com/albums/2/photos?_limit=3[, ...]) once (never called)

¡Excelente! ¡Estamos bastante seguros de que nuestras simulaciones garantizarán que nuestra función se comporte como esperamos!

Al usar un simulacro, hemos podido obtener los beneficios tanto de los espías como de los talones. Pudimos comprobar que nuestra función fue llamada exactamente una vez, y con los argumentos correctos, un beneficio que nos proporcionaron los espías. También pudimos eliminar la solicitud para no realizar una llamada HTTP real a la API, lo que aseguró que nuestra prueba se ejecutara rápidamente.

Conclusión

Los simulacros en las pruebas unitarias combinan la funcionalidad tanto de espías como de stubs reemplazando funciones como stubs y al mismo tiempo proporcionándonos los medios para observar las funciones para comprobar cómo fueron llamadas, la funcionalidad que nos proporcionan los espías. Los simulacros nos brindan el beneficio de verificar cómo se usó nuestra función en una prueba.

En este artículo, presentamos el concepto de burlarse de las pruebas unitarias y vimos cómo podemos burlarnos de una llamada HTTP. Para obtener más información sobre las simulaciones de Sinon.js, puede revisar el documentación oficial de la API de simulacros.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad