Escribir pruebas unitarios es una parte muy importante del ciclo de desarrollo. La mayoría de código es fácil de probar: hay una entrada y nos aseguramos que la salida sea la correcta. Pero las cosas se comienzan a poner interesantes cuando introducimos llamadas a la red. Es bastante fácil levantar un API y escribir pruebas de integración, pero en caso de que no queramos todo ese trabajo extra que le añade dependencias a nuestras pruebas nock tiene la solución.

Nock obtiene su nombre de las palabras en ingles “network mock“, y es una librería para simular llamadas HTTP. Y funciona bien con las librerías incluidas en node para solicitudes http y https, ademas de otras librerías que usan esas interfaces como superagent o axios.

Comenzar a trabajar con nock es bastante estándar, todo lo que tenemos que hacer es agregar la dependencia a nuestro proyecto. Es recomendable instalarla como dependencia de desarrollo ya que en situaciones normales esto no se usa en producción.

Para instalarlo como dependencia de desarrollo usamos la bandera –save-dev:

$ npm install nock --save-dev

Y luego para usarlo necesitamos añadirlo a nuestro script de pruebas:

const nock = require('nock');

Nock trabaja simulando llamadas a la red o interceptores. El objeto nock recibe un host y subsecuentemente construimos el método del request (.get(), .post(), .put() or .delete()) que queremos simular.

Cuando construimos el request, debemos pasar la URI como el primer argumento y opcionalmente el contenido del request después de eso.

Por ultimo lo que necesitamos hacer es especificar la respuesta del servidor que estamos simulando. .reply() acepta un código de estado HTTP como el primer argumento y opcionalmente el contenido de la respuesta.

Poniendo un ejemplo de todo esto el código se vería así:

nock('https://ricardogeek.com')
  .post('/fake', { id: '123' })
  .reply(200, { status: 'OK' });

Simulando La Red

Antes de ejecutar el código que hace la llamada a la red que necesitamos probar, debemos poner una llamada simulada que sera usada en lugar de la verdadera en el código.

nock('https://ricardogeek.com')
  .get('/get')
  .reply(200, {
    "args": {},
    "headers": {
      "Accept": "application/json",
      "Accept-Encoding": "gzip, deflate",
      "Accept-Language": "en-US",
      "url": "https://ricardogeek.com"
    }
  });

obtenerDatos();

El código anterior regresa exitosamente con un 200 OK y un contenido que imita lo que regresa la url dada en la vida rea. Todo sin hacer la llamada real. Es decir, supongamos que obtenerDatos() es una función de nuestra aplicación y obtiene datos de este sitio, entonces para la prueba unitaria describimos en el nock lo que la red contesta y cuando la función lo obtiene nock intercepta esa llamada y devuelve el resultado simulado.

Quizás lo que perdemos es un test de integración real, pero ganamos velocidad en las pruebas y dejamos de depender de un servicio de terceros para que estas corran.

Es es muy útil cuando tenemos un proceso como parte de nuestra integración continua en la que los tests tienen que pasar antes de que el proyecto pueda ser instalado.

Internamente, nock mantiene una lista de estos interceptores y conforme van siendo usados los quita de la lista. Es decir que cada nock solo se puede usar una vez durante la prueba, por lo que debemos asegurarnos de que cuando hacemos una prueba exista un interceptor en la lista para atender la prueba.

Como los interceptores se usan en el orden en el que han sido creados, si definimos múltiples interceptores que van a la misma dirección pero regresan diferentes contenidos debemos ser cuidadosos de usarlos en el mismo orden.

Simulando Errores

Uno de los usos principales que se le puede dar a esta librería es simular una llamada fallida a un servicio de terceros. Normalmente los APIs no proveen formas en las que podamos probar cuando algo va mal, por lo que simular estos escenarios es de mucha utilidad para incrementar la resiliencia de nuestras aplicaciones ante errores externos.

Como estamos simulando las llamadas a la red no importa que los APIs no provean una forma de probar. Simplemente simulamos una llamada mal hecha para comprobar si estamos manejando bien el error.

Digamos que queremos probar que tan bien nuestra aplicación maneja los errores 5xx:

nock('https://ricardogeek.com')
  .post('/post')
  .reply(500);

// usar las funciones de red que deben fallar y comprobar

Lo anterior es genial porque nos permite tener una cobertura de pruebas del 100%, ya no hay excusas.

Categorized in:

Tagged in:

, , ,