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:
-
Cuando la suite se vuelve más compleja, el comportamiento de la suite ya no corresponde a nada sensato.
-
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.