Introducción a Jasmine Pruebas unitarias

Jasmine es la biblioteca JS más popular para pruebas unitarias de aplicaciones web. En este tutorial, diseñado para principiantes, le presentaremos una guía rápida y completa para probar con Jasmine.

Conocerás Jasmine, un popular framework de pruebas basado en el comportamiento para JavaScript. También veremos un ejemplo práctico y sencillo sobre cómo escribir pruebas unitarias con Jasmine, que puede ayudarte a comprobar fácilmente si hay errores en tu código.

En pocas palabras, veremos cómo escribir conjuntos de pruebas, especificaciones y expectativas y cómo aplicar matchers Jasmine incorporados o crear sus propios matchers personalizados

También veremos cómo puede agrupar suites para organizar sus pruebas para bases de código más complejas.

Presentamos Jasmine

Jasmine es un framework de desarrollo basado en el comportamiento de JavaScript muy popular (En BDD, se escriben pruebas antes de escribir código real) para pruebas unitarias de aplicaciones JavaScript. Proporciona utilidades que se pueden usar para ejecutar pruebas automatizadas de código síncrono y asíncrono.

Jasmine tiene muchas características como:

  • Es rápido y tiene una sobrecarga baja y sin dependencias externas.
  • Es una biblioteca con baterías incluidas y ofrece todo lo que necesita para probar su código.
  • Está disponible tanto para el nodo como para el navegador.
  • Se puede usar con otros lenguajes como Python y Ruby.
  • No requiere el DOM.
  • Proporciona una sintaxis limpia y fácil de entender y también una API rica y sencilla.
  • Podemos utilizar el lenguaje natural para describir las pruebas y los resultados esperados.

Jasmine es una herramienta de código abierto que está disponible bajo la licencia MIT permisiva. Al momento de escribir este artículo, la última versión principal es Jasmine 3.0, que proporciona nuevas características y algunos cambios radicales. La versión 2.99 de Jasmine proporcionará diferentes advertencias de obsolescencia para las suites que tienen un comportamiento diferente en la versión 3.0, lo que facilitará a los desarrolladores la migración a la nueva versión.

Puede leer sobre las nuevas funciones y los cambios de interrupción en este documento.

Usando Jasmine

Puedes usar Jasmine de muchas maneras diferentes:

  • a la antigua usanza, incluyendo tanto el núcleo de Jasmine como sus archivos de prueba utilizando una etiqueta <script>,
  • como herramienta de CLI utilizando el Nodo.js,
  • como biblioteca en el nodo.js,
  • como parte de un sistema de compilación como Gulp.js o Grunt.js a través de grunt-contrib-jasmine y gulp-jasmine-browser

También puede usar Jasmine para probar su código Python con jasmine-py, que se puede instalar desde PyPI utilizando el comando pip install jasmine. Este paquete contiene un servidor web que sirve y ejecuta una suite Jasmine para su proyecto y un script CLI para ejecutar pruebas e integraciones continuas.

Jasmine también está disponible para proyectos de Ruby a través de jasmine-gem, que se puede instalar agregando gem 'jasmine' a su Gemfile y ejecutando bundle install. Incluye un servidor para servir y ejecutar pruebas, un script CLI y también generadores para proyectos Ruby on Rails.

Ahora vamos a centrarnos en cómo usar Jasmine con JavaScript:

Usando Jasmine independiente

Comience descargando la última versión de Jasmine desde la página de lanzamientos.

a Continuación, simplemente extrae el archivo zip, preferentemente dentro de una carpeta en el proyecto que desea probar.

La carpeta contendrá un montón de carpetas y archivos predeterminados:

/src: contiene los archivos de origen que desea probar. Esto puede eliminarse si ya tiene configurada la carpeta de su proyecto o también puede usarse cuando sea apropiado para alojar su código fuente.

/lib: contiene los archivos principales de Jasmine.

/spec: contiene las pruebas que va a escribir.

SpecRunner.html : este archivo se utiliza como ejecutor de pruebas. Ejecute sus especificaciones simplemente iniciando este archivo.

Este es el contenido de un archivo predeterminado SpecRunner.html:

<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>Jasmine Spec Runner v3.2.1</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-3.2.1/jasmine_favicon.png"> <link rel="stylesheet" href="lib/jasmine-3.2.1/jasmine.css"> <script src="lib/jasmine-3.2.1/jasmine.js"></script> <script src="lib/jasmine-3.2.1/jasmine-html.js"></script> <script src="lib/jasmine-3.2.1/boot.js"></script> <!-- include source files here... --> <script src="src/Player.js"></script> <script src="src/Song.js"></script> <!-- include spec files here... --> <script src="spec/SpecHelper.js"></script> <script src="spec/PlayerSpec.js"></script></head><body></body></html>

Recuerde que debe cambiar los archivos incluidos de las carpetas /src y /spec para contener los archivos de origen y de prueba reales.

Usando Jasmine como biblioteca

También puedes usar Jasmine como biblioteca en tu proyecto. Por ejemplo, el siguiente código importa y ejecuta Jasmine:

var Jasmine = require('jasmine');var jasmine = new Jasmine();jasmine.loadConfigFile('spec/support/jasmine.json');jasmine.execute();

Primero requerimos / import Jasmine y usamos el método loadConfigFile() para cargar el archivo de configuración disponible desde spec/support/jasmine.json y finalmente ejecutamos Jasmine.

Usando Jasmine a través de la CLI

También puede usar Jasmine desde la CLI, que le permite ejecutar fácilmente pruebas de Jasmine y, de forma predeterminada, generar los resultados en el terminal.

Seguiremos este enfoque para ejecutar nuestras pruebas de ejemplo en esta guía, así que primero ejecute el siguiente comando para instalar Jasmine globalmente:

npm install -g jasmine

Es posible que necesite ejecutar sudo para instalar paquetes npm globalmente dependiendo de su configuración npm.

Ahora, cree una carpeta para su proyecto y navegue dentro de ella:

$ mkdir jasmine-project $ cd jasmine-project

A continuación, ejecute el siguiente comando para inicializar su proyecto para Jasmine:

Este comando simplemente crea una carpeta de especificaciones y un archivo de configuración JSON. Esta es la salida de la etiqueta dir comandos:

.└── spec └── support └── jasmine.json2 directories, 1 file

Este es el contenido de un defecto jasmine.json archivo:

{ "spec_dir": "spec", "spec_files": pec.js" ], "helpers": , "stopSpecOnExpectationFailure": false, "random": true}
  • spec_dir: especifica dónde Jazmín busca archivos de prueba.
  • spec_files: especifica los patrones de los archivos de prueba, de forma predeterminada todos los archivos JS que terminan con especificaciones o cadenas de especificaciones.
  • helpers: especifica dónde Jasmine busca los archivos auxiliares. Los archivos auxiliares se ejecutan antes de las especificaciones y se pueden usar para definir coincidencias personalizadas.
  • stopSpecOnExpectationFailure : cuando se establece en true, se detiene inmediatamente una especificación en el primer fallo de una expectativa (se puede usar como opción de CLI a través de --stop-on-failure).
  • random : cuando se establece en true, Jasmine ejecutará pseudo-aleatoriamente los casos de prueba (se puede usar como una opción de CLI a través de --random).

Las matrices spec_files y helpers también pueden contener patrones Glob (gracias al paquete node-glob) para especificar rutas de archivo que son patrones que normalmente usa para especificar un conjunto de archivos cuando trabaja en Bash (por ejemplo, ls *.js).

Si no utiliza la ubicación predeterminada para el archivo de configuración jasmine.json, simplemente debe especificar la ubicación personalizada a través de la opción jasmine --config.

Puedes encontrar más opciones de CLI en los documentos oficiales.

Entendiendo Jasmine

En esta sección aprenderemos sobre los elementos básicos de las pruebas de Jasmine, como suites, especificaciones, expectativas, emparejadores y espías, etc.

En la carpeta de su proyecto, ejecute el siguiente comando para inicializar un nuevo módulo de nodo:

Esto creará un archivo package.json con información predeterminada:

{ "name": "jasmine-project", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": , "author": "", "license": "ISC"}

A continuación, cree un archivo index.js y agregue el siguiente código:

function fibonacci(n){ if (n === 1) { return ; } else { var s = fibonacci(n - 1); s.push(s + s); return s; }}function isPrime(num){ for (let i = 2; i < num; i++) if (num % i === 0) return false; return num !== 1 && num !== 0;}function isEven(n) { return n % 2 == 0;}function isOdd(n) { return Math.abs(n % 2) == 1;}function toLowerCase(str){ return str.toLowerCase();}function toUpperCase(str){ return str.toUpperCase();}function contains(str, substring, fromIndex){ return str.indexOf(substring, fromIndex) !== -1;}function repeat(str, n){ return (new Array(n + 1)).join(str);}module.exports = { fibonacci: fibonacci, isPrime: isPrime, isEven: isEven, isOdd: isOdd, toLowerCase: toLowerCase, toUpperCase: toUpperCase, contains: contains, repeat: repeat};

Suites

Una suite agrupa un conjunto de especificaciones o casos de prueba. Se utiliza para probar un comportamiento específico del código JavaScript que normalmente está encapsulado por un objeto/clase o una función. Se crea utilizando la función global Jasmine describe() que toma dos parámetros, el título del conjunto de pruebas y una función que implementa el código real del conjunto de pruebas.

Comencemos creando nuestro primer conjunto de pruebas. Dentro de la carpeta spec cree un archivo MyJSUtilitiesSpec.js y agregue:

describe("MyJSUtilities", function() { /* ... */ });

MyJSUtilities es el nombre de este conjunto de pruebas de nivel superior.

Cómo agrupar y Anidar Suites

Para organizar mejor y describir con precisión nuestro conjunto de pruebas, podemos anidar suites dentro de la suite de nivel superior. Por ejemplo, agreguemos dos suites a la suite de MyJSUtilities:

describe("String Utils", function() { /*...*/});describe("Math Utils", function() { /*...*/});

Dentro de la suite de Utilidades Matemáticas, también agreguemos dos suites anidadas:

describe("Basic Math Utils", function() { /* ... */ }); describe("Advanced Math Utils", function() { /* ... */ });

Estamos agrupando pruebas relacionadas en pruebas para Utilidades de Cadena, Utilidades Matemáticas Básicas y Utilidades Matemáticas Avanzadas y anidándolas dentro del nivel superior suite de pruebas MyJSUtilities. Esto compondrá sus especificaciones como árboles similares a una estructura de carpetas.

La estructura de anidamiento se mostrará en el informe, lo que le facilita encontrar pruebas fallidas.

Cómo excluir suites

Puede desactivar temporalmente una suite con la función xdescribe(). Tiene la misma firma (parámetros) que una función describe(), lo que significa que puede deshabilitar rápidamente sus suites existentes simplemente agregando un x a la función.Las especificaciones

dentro de una función xdescribe() se marcarán pendientes y no se ejecutarán en el informe.

Especificaciones

Una especificación declara un caso de prueba que pertenece a un conjunto de pruebas. Esto se hace llamando a la función global Jasmine it() que toma dos parámetros, el título de la especificación (que describe la lógica que queremos probar) y una función que implementa el caso de prueba real.

Una especificación puede contener una o más expectativas. Cada expectativa es simplemente una afirmación que puede devolver true o false. Para que se pase la especificación, todas las expectativas que pertenecen a la especificación deben ser true de lo contrario, la especificación falla.

Dentro de nuestra suite String Utils, agregue estas especificaciones:

describe("String Utils", function() { it("should be able to lower case a string",function() { /*...*/ }); it("should be able to upper case a string",function() { /*...*/ }); it("should be able to confirm if a string contains a substring",function() { /*...*/ }); it("should be able repeat a string multiple times",function() { /*...*/ });});

Dentro de nuestra suite Basic Math Utils, agreguemos algunas especificaciones:

describe("Basic Math Utils", function() { it("should be able to tell if a number is even",function() { /*...*/ }); it("should be able to tell if a number is odd",function() { /*...*/ }); });

Para los Utils Avanzados de Matemáticas, agreguemos las especificaciones:

describe("Advanced Math Utils", function() { it("should be able to tell if a number is prime",function() { /*...*/ }); it("should be able to calculate the fibonacci of a number",function() { /*...*/ }); });

Cómo excluir especificaciones

Al igual que las suites, también puede excluir especificaciones individuales utilizando la función xit()que deshabilita temporalmente la especificación it() y marca la especificación como pendiente.

Expectativas

Las expectativas se crean utilizando la función expect() que toma un valor llamado real (esto puede ser valores, expresiones, variables, funciones u objetos, etc.). Las expectativas componen la especificación y se utilizan junto con las funciones de comparación (mediante encadenamiento) para definir lo que el desarrollador espera de una unidad de código específica para realizar.

Una función de comparación compara entre un valor real (pasado a la función expect() con la que está encadenada) y un valor esperado (pasado directamente como parámetro al comparador) y devuelve verdadero o falso que pasa o falla la especificación.

Puede encadenar la función expect() con varios emparejadores. Para negar/invertir el resultado booleano de cualquier matcher, puede usar la palabra clave not antes de llamar al matcher.

Implementemos las especificaciones de nuestro ejemplo. Por ahora usaremos usaremos expect()nothing() comparador que es parte de la incorporada en los dispositivos de comparación que veremos un poco más adelante. Esto pasará todas las especificaciones, ya que no esperamos nada en este momento.

describe("MyJSUtilities", function() {describe(">String Utils", function() { it("should be able to lower case a string",function() { expect().nothing(); }); it("should be able to upper case a string",function() { expect().nothing(); }); it("should be able to confirm if a string contains a substring",function() { expect().nothing(); }); it("should be able repeat a string multiple times",function() { expect().nothing(); }); });describe("Math Utils", function() { describe("Basic Math Utils", function() { it("should be able to tell if a number is even",function() { expect().nothing(); }); it("should be able to tell if a number is odd",function() { expect().nothing(); }); }); describe("Advanced Math Utils", function() { it("should be able to tell if a number is prime",function() { expect().nothing(); }); it("should be able to calculate the fibonacci of a number",function() { expect().nothing(); }); }); });});

Esta es una captura de pantalla de los resultados en este punto:

Hemos pasado ocho especificaciones y cero fallos.

Puede usar emparejadores integrados o también crear sus propios emparejadores personalizados para sus necesidades específicas.

Emparejadores incorporados

Jasmine proporciona un rico conjunto de emparejadores incorporados. Veamos algunos de los más importantes:

  • toBe() para la prueba de identidad,
  • toBeNull() para la prueba de null,
  • toBeUndefined()/toBeDefined() para la prueba de undefined/no undefined,
  • toBeNaN() para el análisis de NaN (No Un Número)
  • toEqual() para las pruebas para la igualdad,
  • toBeFalsy()/toBeTruthy() para la prueba de la falsedad/veracidad etc.

Puede encontrar la lista completa de emparejadores en los documentos.

Ahora implementemos nuestras especificaciones con algunos de estos emparejadores cuando sea apropiado. Primero importe las funciones que estamos probando en nuestro archivo MyJSUtilitiesSpec.js:

const utils = require("../index.js");

A continuación, comience con la cadena Utils suite y cambie expect().nothing() con las expectativas adecuadas.

Por ejemplo, para la primera especificación, esperamos que el método toLowerCase() se defina primero y, en segundo lugar, devuelva una cadena en minúsculas, es decir:

it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); });

Este es el código completo de la suite:

describe(">String Utils", function() { it("should be able to lower case a string",function() { expect(utils.toLowerCase).toBeDefined(); expect(utils.toLowerCase("HELLO WORLD")).toEqual("hello world"); }); it("should be able to upper case a string",function() { expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); }); it("should be able to confirm if a string contains a substring",function() { expect(utils.contains).toBeDefined(); expect(utils.contains("hello world","hello",0)).toBeTruthy(); }); it("should be able repeat a string multiple times",function() { expect(utils.repeat).toBeDefined(); expect(utils.repeat("hello", 3)).toEqual("hellohellohello"); }); });

Matchers personalizados

Jasmine proporciona la capacidad de escribir matchers personalizados para implementar aserciones no cubiertas por los matchers incorporados o simplemente para hacer que las pruebas sean más descriptivas y legibles.

Por ejemplo, tomemos el siguiente especificación:

it("should be able to tell if a number is even",function() { expect(utils.isEven).toBeDefined(); expect(utils.isEven(2)).toBeTruthy(); expect(utils.isEven(1)).toBeFalsy(); });

supongamos que el isEven() método no está implementado. Si ejecutamos las pruebas obtendremos mensajes como la siguiente captura de pantalla:

El mensaje de error que recibimos dice que se espera indefinido, lo que no nos da idea de lo que está sucediendo. Así que hagamos que este mensaje sea más significativo en el contexto de nuestro dominio de código (esto será más útil para bases de código complejas). Para este asunto, vamos a crear un emparejador personalizado.

Creamos matchers personalizados utilizando el método addMatchers() que toma un objeto compuesto por una o varias propiedades que se agregarán como matchers. Cada propiedad debe proporcionar una fábrica de función que toma dos parámetros: util, que tiene un conjunto de funciones de utilidad para los dispositivos de comparación a utilizar (véase: matchersUtil.js) y customEqualityTesters, que debe ser aprobada en si util.equals se llama, y debe devolver un objeto con un compare función que será llamada para comprobar la expectativa.

Necesitamos registrar el matcher personalizado antes de ejecutar cada especificación utilizando el método beforeEach() :

describe("/Basic Math Utils", function () {beforeEach(function () {jasmine.addMatchers({hasEvenMethod: function (util, customEqualityTesters) {return {compare: function (actual, expected) {var result = { pass: utils.isEven !== undefined };if (result.pass) {result.message = "Expected isEven() to be not defined."}else {result.message = "Expected isEven() to be defined."}return result;}}}});});/*...*/});

Luego podemos usar el emparejador personalizado en lugar de expect(utils.isEven).toBeDefined():

expect().hasEvenMethod();

Esto nos dará un mejor mensaje de error:

Usando beforeEach() y afterEach()

Para inicializar y limpiar sus especificaciones, Jasmine proporciona dos funciones globales, beforeEach() y afterEach():

  • La función beforeEach se llama una vez antes de cada especificación en la suite donde se llama.
  • La función afterEach se llama una vez después de cada especificación en la suite donde se llama.

Por ejemplo, si necesita usar alguna variable en su conjunto de pruebas, simplemente puede declararla al inicio de la función describe() y poner cualquier código de inicialización o creación de instancias dentro de una función beforeEach(). Finalmente, puede usar la función afterEach() para restablecer las variables después de cada especificación, de modo que pueda tener pruebas unitarias puras sin la necesidad de repetir el código de inicialización y limpieza para cada especificación.

La función beforeEach() también se combina perfectamente con muchas API de Jasmine, como el método addMatchers() para crear emparejadores personalizados o también con la función done() para esperar operaciones asincrónicas antes de continuar las pruebas.

Fallo en una prueba

Puede forzar el fallo de una prueba utilizando el método global fail() disponible en Jasmine. Por ejemplo:

it("should explicitly fail", function () { fail('Forced to fail'); });

Debería obtener el siguiente error:

Prueba de excepciones

Cuando está probando unitariamente su código, es posible que tenga que probar estos escenarios. Jasmine proporciona los emparejadores toThrow() y toThrowError() para comprobar cuando se lanza una excepción o para comprobar una excepción específica, respectivamente.

Por ejemplo, si tenemos una función que arroja una excepción TypeError :

function throwsError() { throw new TypeError("A type error"); }

podría escribir una especificación que para comprobar si se produce una excepción:

it('it should throw an exception', function () { expect(throwsError).toThrow(); });

O, usted podría también utilizar probar el TypeError excepción:

it('it should throw a TypeError', function () { expect(throwsError).toThrowError(TypeError); });

la Comprensión de los Espías

Más a menudo que no, los métodos dependen de otros métodos. Esto significa que cuando está probando un método, también puede terminar probando sus dependencias. Esto no se recomienda en las pruebas, es decir, debe asegurarse de probar la función pura aislando el método y viendo cómo se comporta dado un conjunto de entradas.

Jasmine proporciona espías que se pueden usar para espiar / escuchar llamadas a métodos en objetos e informar si se llama a un método y con qué contexto y argumentos.Jasmine proporciona dos formas de espiar llamadas a métodos: usando los métodos spyOn() o createSpy().

puede utilizar spyOn() cuando el método ya existe en el objeto, de lo contrario tendrá que usar jasmine.createSpy() que devuelve una nueva función.

De forma predeterminada, un espía solo reportará si se realizó una llamada sin llamar a través de la función espiada (i.e la función dejará de ejecutarse), pero puede cambiar el comportamiento predeterminado utilizando estos métodos:

  • and.callThrough(): llamar a través de la función original,
  • and.returnValue(value): devolver el valor especificado,
  • and.callFake(fn): llamar a la función función falsa en lugar de la original,
  • and.throwError(err): arroja un error,
  • and.stub(): restablece el comportamiento de stubbing predeterminado.

Puede usar un espía para recopilar estadísticas en tiempo de ejecución de la función espiada, por ejemplo, si desea saber cuántas veces se llamó a su función.

Digamos que queremos asegurarnos de que nuestro método toUpperCase() está haciendo uso del método incorporado String.toUpperCase(), simplemente necesitamos espiar String.toUpperCase() utilizando:

it("should be able to upper case a string", function () { 
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase') 
expect(utils.toUpperCase).toBeDefined(); expect(utils.toUpperCase("hello world")).toEqual("HELLO WORLD"); expect(String.prototype.toUpperCase).toHaveBeenCalled(); expect(spytoUpperCase.calls.count()).toEqual(1); });

La prueba ha fallado debido a la segunda expectativa, porque utils.toUpperCase("hello world") devuelve undefined en lugar de la esperada HOLA MUNDO. Esto se debe a que, como mencionamos anteriormente, después de crear el espía en toUpperCase(), el método no se ejecuta. Necesitamos cambiar este comportamiento predeterminado llamando a callThrough():

Tenga en cuenta que una función spy reemplaza la función espiada por un stub de forma predeterminada. Si necesita llamar a la función original, puede agregar .and.callThrough() a su objeto spy

var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callThrough();

Ahora todas las expectativas pasar.

También puede usar and.callFake() o and.returnValue() para falsificar la función spied on o simplemente el valor devuelto si no llama a través de la función real:

var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.returnValue("HELLO WORLD"); 
var spytoUpperCase = spyOn(String.prototype, 'toUpperCase').and.callFake(function(){ return "HELLO WORLD"; });

Ahora, si no terminamos utilizando el construido en el String.toUpperCase() en nuestra utils.toUpperCase() aplicación, vamos a obtener estos errores:

Los dos expectativas expect(String.prototype.toUpperCase).toHaveBeenCalled()expect(spytoUpperCase.calls.count()).toEqual(1) han fracasado.

Cómo lidiar con la asincronicidad en Jasmine

Si el código que está probando contiene operaciones asincrónicas, necesita una forma de que Jasmine sepa cuándo se han completado las operaciones asincrónicas.

De forma predeterminada, Jasmine espera a que finalice cualquier operación asíncrona, definida por una devolución de llamada, promesa o la palabra clave async. Si Jazmín encuentra una devolución de llamada, promesa o palabra clave async en una de estas funciones: beforeEachafterEachbeforeAllafterAll y it esperará para que el asincrónica por hacer antes de proceder a la siguiente operación.

Usando done () con beforeEach () / it ()..

tomemos nuestro ejemplo simulateAsyncOp() que simula una operación asincrónica utilizando setTimeout(). En un escenario del mundo real, esto puede ser una solicitud Ajax o cualquier cosa similar que suceda de forma asíncrona:

function simulateAsyncOp(callback){ 
setTimeout(function () { callback(); }, 2000); }

Para probar esta función podemos usar la función beforeEach() con la función especial done() devolución de llamada. Nuestro código necesita invocar done() para decirle a Jasmine que la operación asíncrona se ha completado:

describe("/Async Op", function () {var asyncOpCompleted = false;beforeEach(function (done) {utils.simulateAsyncOp(function(){ asyncOpCompleted = true; done();});});it("should be able to tell if the async call has completed", function () { expect(asyncOpCompleted).toEqual(true);});});

Rápidamente podemos notar un inconveniente de este método, por lo que necesitamos escribir nuestro código para aceptar la devolución de llamada done(). En nuestro caso, no codificamos el método done() en nuestro simulateAsyncOp(fn), pero hemos proporcionado un parámetro de devolución de llamada solo para poder llamar a done().

Usando Promises

Si no desea crear código que dependa de cómo escriba su prueba, puede usar una promesa en su lugar y llamar a la devolución de llamada done() cuando la promesa se haya resuelto. O mejor aún, en Jasmine 2.7+, si su código devuelve un Promise, Jasmine esperará hasta que se resuelva o rechace antes de ejecutar el siguiente código.

Utilizando async/await

Jasmine 2.7 + admite llamadas async y await en especificaciones. Esto alivia de poner afirma en un .then() o .catch() bloquear.

it("should work with async/await", async () => { let completed = false; completed = await utils.simulateAsyncOp(); expect(completed).toEqual(true); });

Esta es la implementación de simulateAsyncOp:

function simulateAsyncOp() { 
return new Promise(resolve => { setTimeout(() => { resolve(true); }, 1000); }); }

Usando Jasmine Clock

El reloj Jasmine se utiliza para probar código asíncrono que depende de funciones de tiempo, como setTimeout() de la misma manera que probamos código síncrono burlándose de API basadas en el tiempo con métodos personalizados. De esta manera, puede ejecutar las funciones probadas de forma sincrónica controlando o avanzando manualmente el reloj.

Puede instalar el reloj Jasmine llamando a la función jasmine.clock().install en su especificación o suite.

Después de usar el reloj, debe desinstalarlo para restaurar las funciones originales.

Con Jasmine clock, puede controlar las funciones de JavaScript setTimeout o setInterval marcando el reloj para avanzar en el tiempo utilizando la función jasmine.clock().tick, que toma el número de milisegundos con los que puede moverse.

También puedes usar el reloj Jasmine para simular la fecha actual.

beforeEach(function () {jasmine.clock().install();});afterEach(function() {jasmine.clock().uninstall();});it("should call the asynchronous operation synchronously", function() {var completed = false;utils.simulateAsyncOp(function(){completed = true;});expect(completed).toEqual(false);jasmine.clock().tick(1001);expect(completed).toEqual(true);});

Este es el simulateAsyncOp función:

function simulateAsyncOp(callback){ 
setTimeout(function () { callback(); }, 1000); }

En caso de no especificar un tiempo para que el mockDate la función de utilizar la fecha actual.

Manejo de errores

Si su código asincrónico falla debido a algún error, desea que sus especificaciones fallen correctamente. A partir de Jasmine 2.6+, cualquier error no controlado se envía a la especificación ejecutada actualmente.

Jasmine también proporciona una forma de usar si necesita fallar explícitamente sus especificaciones:

  • con el done() devolución de llamada con la etiqueta beforeEach() llamando al done.fail(err) método
  • simplemente pasando un error en el done(err) callback (Jazmín 3+),
  • llamada reject() método de un Promise.

Conclusión

En esta guía hemos presentado Jasmine y hemos visto cómo empezar a usar Jasmine para probar unitariamente tu código JavaScript. Gracias por leer!

Este artículo fue publicado originalmente en techiediaries.

Deja una respuesta

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