node.js mocha

node.js - ¿Cómo puedo construir mi conjunto de pruebas de forma asincrónica?



mocha (3)

Estoy tratando de crear pruebas de mocha para mis controladores usando una configuración que debe cargarse de forma asíncrona. Abajo está mi código. Sin embargo, cuando se ejecuta la prueba de mocha, no ejecuta ninguna prueba, mostrando 0 passing . Los console.log s ni siquiera se llaman. Intenté hacer before(next => config.build().then(next)) dentro de la descripción, pero a pesar de que las pruebas se ejecutan, before nunca se llama. ¿Hay alguna forma de cargar la configuración una vez antes de ejecutar cualquier prueba?

''use strict''; const common = require(''./common''); const config = require(''../config''); config .build() .then(test); function test() { console.log(1); describe(''Unit Testing'', () => { console.log(2); require(''./auth''); }); }


Debe ejecutar Mocha con la opción --delay , y luego usar run() una vez que haya terminado de construir su conjunto de pruebas. Aquí hay un ejemplo derivado del código que muestra en la pregunta:

''use strict''; function test() { console.log(1); describe(''Unit Testing'', () => { console.log(2); it("test", () => { console.log(3); }); }); // You must use --delay for `run()` to be available to you. run(); } setTimeout(test, 1000);

Estoy usando setTimeout para simular una operación asincrónica. El uso de --delay and run() permite crear una suite que es el resultado de un cálculo asincrónico. Sin embargo, tenga en cuenta que la suite debe construirse de una sola vez. (No puede tener un proceso asincrónico dentro de la describe que haga llamadas a it . Esto no funcionará).

Una cosa que definitivamente no debe hacer es lo que suggests rob3c: llamar a describe o it (o ambos) desde el interior de un gancho. Este es un error que de vez en cuando comete la gente, por lo que vale la pena abordarlo en detalle. El problema es que simplemente no es compatible con Mocha y, por lo tanto, no hay una semántica establecida asociada con la llamada a describe o desde dentro de un gancho. Oh, es posible escribir ejemplos simples que funcionen como uno podría esperar pero:

  1. Cuando la suite se vuelve más compleja, el comportamiento de la suite ya no corresponde a nada sensato.

  2. Dado que no hay una semántica asociada con este enfoque, las nuevas versiones de Mocha pueden manejar el uso erróneo de manera diferente y romper su suite.

Considere este simple ejemplo:

const assert = require("assert"); const p = Promise.resolve(["foo", "bar", "baz"]); describe("top", () => { let flag; before(() => { flag = true; return p.then((names) => { describe("embedded", () => { for (const name of names) { it(name, () => { assert(flag); }); } }); }); }); after(() => { flag = false; }); it("regular test", () => { assert(flag); }); });

Cuando lo ejecutamos, obtenemos:

top ✓ regular test embedded 1) foo 2) bar 3) baz 1 passing (32ms) 3 failing // [stack traces omitted for brevity]

¿Que está pasando aqui? ¿No deberían pasar todas las pruebas? Establecemos flag en true en el hook before para la descripción top . Todas las pruebas que creamos en él deberían ver la flag como true , ¿no? La pista está en el resultado anterior: cuando creamos pruebas dentro de un gancho, Mocha colocará las pruebas en algún lugar, pero puede que no esté en una ubicación que refleje la estructura de los bloques de describe en el código. Lo que sucede en este caso es que Mocha solo agrega las pruebas creadas en el gancho al final de la suite, fuera de la descripción top , por lo que el gancho after ejecuta antes de las pruebas creadas dinámicamente, y obtenemos un resultado contrario a la intuición.

Usando --delay y run() , podemos escribir una suite que se comporte de acuerdo con la intuición:

const assert = require("assert"); const p = Promise.resolve(["foo", "bar", "baz"]).then((names) => { describe("top", () => { let flag; before(() => { flag = true; }); after(() => { flag = false; }); describe("embedded", () => { for (const name of names) { it(name, () => { assert(flag); }); } }); it("regular test", () => { assert(flag); }); }); run(); });

Salida:

top ✓ regular test embedded ✓ foo ✓ bar ✓ baz 4 passing (19ms)


El problema con el uso del --delay línea de comando --delay y la devolución de llamada run() que @Louis mencionó en su respuesta aceptada, es que run() es un enlace global único que retrasa el conjunto de pruebas raíz . Por lo tanto, debe construirlos todos a la vez (como mencionó), lo que puede hacer que la organización de las pruebas sea una molestia (por decir lo menos).

Sin embargo, prefiero evitar las banderas mágicas siempre que sea posible, y ciertamente no quiero tener que administrar todo mi conjunto de pruebas en una única devolución de llamada global run() . Afortunadamente, hay una manera de crear dinámicamente las pruebas por archivo, y no requiere ningún indicador especial, tampoco :-)

Para crear dinámicamente pruebas It() en cualquier archivo fuente de prueba utilizando datos obtenidos de forma asincrónica, puede (ab) usar el gancho before() con una prueba de marcador de posición It() para garantizar que el mocha espere hasta que se ejecute before() . Aquí está el ejemplo de mi respuesta a una pregunta relacionada , por conveniencia:

before(function () { console.log(''Let the abuse begin...''); return promiseFn(). then(function (testSuite) { describe(''here are some dynamic It() tests'', function () { testSuite.specs.forEach(function (spec) { it(spec.description, function () { var actualResult = runMyTest(spec); assert.equal(actualResult, spec.expectedResult); }); }); }); }); }); it(''This is a required placeholder to allow before() to work'', function () { console.log(''Mocha should not require this hack IMHO''); });


Simplemente puede separar la lógica de las pruebas y la carga por completo, envolver el cargador en una promesa que bloquea la prueba hasta que se ejecute la configuración (muy sencillo con async / wait si está usando el nodo 8, de lo contrario, solo Promise. Cada resultado).

Si realmente no quieres hacer eso, puedes Promisificar tu marco de prueba, lo que te permitirá tratar todos los bloques describe / it como código asíncrono.