En las pruebas de mocha al llamar a la función asincrónica, cómo evitar el tiempo de espera Error: se excedió el tiempo de espera de 2000 ms

200

En mi aplicación de nodo, estoy usando mocha para probar mi código. Al llamar a muchas funciones asincrónicas usando mocha, obtengo un error de tiempo de espera ( Error: timeout of 2000ms exceeded.). ¿Cómo puedo resolver esto?

var module = require('../lib/myModule');
var should = require('chai').should();

describe('Testing Module', function() {

    it('Save Data', function(done) {

        this.timeout(15000);

        var data = {
            a: 'aa',
            b: 'bb'
        };

        module.save(data, function(err, res) {
            should.not.exist(err);
            done();
        });

    });


    it('Get Data By Id', function(done) {

        var id = "28ca9";

        module.get(id, function(err, res) {

            console.log(res);
            should.not.exist(err);
            done();
        });

    });

});
sachin
fuente
¿Es una prueba de integración? es mucho tiempo para que se ejecute una prueba, tal vez debería considerar los talones, github.com/thlorenz/proxyquire podría ayudarlo.
surui
@surui gracias, lo miraré
sachin
¿Puedo recomendar el uso de promesas para cosas asincrónicas y probarlas? Entonces es muy fácil con Chai como promesa
Krym

Respuestas:

344

Puede configurar el tiempo de espera al ejecutar su prueba:

mocha --timeout 15000

O puede establecer el tiempo de espera para cada suite o cada prueba mediante programación:

describe('...', function(){
  this.timeout(15000);

  it('...', function(done){
    this.timeout(15000);
    setTimeout(done, 15000);
  });
});

Para más información ver los documentos .

Andreas Hultgren
fuente
3
versión más corta es -t. si usa mocha-test para ejecutar mocha desde la tarea grunt, esto también es compatible con el objeto de opciones options:{timeout:15000}.
svassr
55
FYI: se desaconseja pasar funciones de flecha a Mocha. mochajs.org/#arrow-functions
llegando
44
Las funciones de flecha no se desaconsejan en el enlace de arriba. Simplemente dice que solo necesita saber qué hacen para no arruinarse cuando necesite acceder al contexto. Nunca necesito el contexto, ya que depender de los tiempos de espera son frágiles y todas mis pruebas se ejecutan en unos pocos ms, pero me encuentro con el mismo problema cuando uso sinon-test. Todavía uso lambdas el 99% del tiempo.
oligofren
26
TypeError: this.timeout is not a functioncuando se usa"mocha": "^3.5.0"
Junior Mayhé
55
@adi ¿estás seguro de que no estás usando las funciones de flecha? En cuanto a async / wait, está en los documentos, por lo que debería funcionar (y es lo mismo que usar promesas). Sin embargo, parece otra pregunta.
Andreas Hultgren
80

Me parece que la "solución" de solo aumentar los tiempos de espera oscurece lo que realmente está sucediendo aquí, que es

  1. Su código y / o llamadas de red son demasiado lentas (deben ser inferiores a 100 ms para una buena experiencia de usuario)
  2. Las afirmaciones (pruebas) están fallando y algo está tragándose los errores antes de que Mocha pueda actuar sobre ellos.

Por lo general, se encuentra con el n. ° 2 cuando Mocha no recibe errores de aserción de una devolución de llamada. Esto es causado por algún otro código que traga la excepción más arriba en la pila. La forma correcta de lidiar con esto es arreglar el código y no tragar el error .

Cuando el código externo se traga tus errores

En caso de que sea una función de biblioteca que no pueda modificar, debe detectar el error de aserción y pasarlo usted mismo a Mocha. Para ello, envuelva su devolución de llamada de aserción en un bloque try / catch y pase cualquier excepción al controlador hecho.

it('should not fail', function (done) { // Pass reference here!

  i_swallow_errors(function (err, result) {
    try { // boilerplate to be able to get the assert failures
      assert.ok(true);
      assert.equal(result, 'bar');
      done();
    } catch (error) {
      done(error);
    }
  });
});

Por supuesto, esta placa repetitiva se puede extraer en alguna función de utilidad para hacer que la prueba sea un poco más agradable a la vista:

it('should not fail', function (done) { // Pass reference here!
    i_swallow_errors(handleError(done, function (err, result) {
        assert.equal(result, 'bar');
    }));
});

// reusable boilerplate to be able to get the assert failures
function handleError(done, fn) {
    try { 
        fn();
        done();
    } catch (error) {
        done(error);
    }
}

Acelerar las pruebas de red

Aparte de eso, le sugiero que siga los consejos sobre cómo comenzar a usar los talones de prueba para las llamadas de red para que las pruebas pasen sin tener que depender de una red en funcionamiento. Usando Mocha, Chai y Sinon, las pruebas podrían verse así

describe('api tests normally involving network calls', function() {

    beforeEach: function () {
        this.xhr = sinon.useFakeXMLHttpRequest();
        var requests = this.requests = [];

        this.xhr.onCreate = function (xhr) {
            requests.push(xhr);
        };
    },

    afterEach: function () {
        this.xhr.restore();
    }


    it("should fetch comments from server", function () {
        var callback = sinon.spy();
        myLib.getCommentsFor("/some/article", callback);
        assertEquals(1, this.requests.length);

        this.requests[0].respond(200, { "Content-Type": "application/json" },
                                 '[{ "id": 12, "comment": "Hey there" }]');
        expect(callback.calledWith([{ id: 12, comment: "Hey there" }])).to.be.true;
    });

});

Vea los nisedocumentos de Sinon para más información.

oligofren
fuente
Tengo un gran conjunto de pruebas y acabo de cumplir todas las promesas en mis especificaciones para asegurarme de que todas estén llamando done()al final de la promesa y ya me estoy burlando de las llamadas de red usando Angular $httpBackend, pero no tuve suerte. Ajustar cada especificación con un try-catch no parece muy pragmático. ¿Cualquier otra sugerencia? ¡Gracias!
Gustavo Matias
@GustavoMatias En realidad no ha mencionado cuál es su problema, simplemente declaró que no es una solución a lo que sea que tenga problemas. Por favor, explique :-) ¿Sus pruebas no fallan lo suficientemente rápido? ¿Están fallando a veces, pero le gustaría saber por qué? Es difícil adivinar lo que pretendes lograr.
oligofren
hola @oligofren! esa no fue la mejor explicación de hecho. Aquí hay una explicación más detallada de mi problema stackoverflow.com/questions/34510048/… ¡gracias!
Gustavo Matias
"En general, la forma más limpia (pero la más fea) de lidiar con este problema es envolver su código con un try / catch y pasar cualquier excepción al controlador hecho". No, esta no es la forma más limpia. Ni por asomo. La forma más limpia es escribir código que no trague excepciones. Cada vez que he visto a alguien quejarse de que Mocha no estaba detectando una prueba fallida, eso fue porque había algo que tragaba la excepción. Agregar un try.... catch...trabajo alrededor del error en el código bajo prueba en lugar de solucionarlo .
Louis
@Louis posiblemente tengas razón sobre los porqués aquí, pero no puedo verificarlo de la nada. de todos modos, la gente tiene un problema con que Mocha aparentemente no puede detectar algún error, y esta es una forma de manejarlo. su enfoque dado supone que el código que se traga el error no es una función de biblioteca o similar, en cuyo caso no se resolvería tan fácilmente.
oligofren
7

Un poco tarde, pero alguien puede usar esto en el futuro ... Puede aumentar el tiempo de espera de la prueba actualizando los scripts en su package.json con lo siguiente:

"scripts": { "test": "test --timeout 10000" //Adjust to a value you need }

Ejecute sus pruebas usando el comando test

Daniel Mbeyah
fuente
¡Trabajó para mi! ¡Gracias!
RayLoveless
5

Si está utilizando funciones de flecha:

it('should do something', async () => {
  // do your testing
}).timeout(15000)
lukas_o
fuente
1

Para mí, el problema era en realidad la función de descripción, que cuando se proporciona una función de flecha, hace que el mocha pierda el tiempo de espera y no se comporte de manera consistente. (Usando ES6)

como no se rechazó ninguna promesa, recibía este error todo el tiempo por diferentes pruebas que fallaban dentro del bloque de descripción

así es como se ve cuando no funciona correctamente:

describe('test', () => { 
 assert(...)
})

y esto funciona usando la función anónima

describe('test', function() { 
 assert(...)
})

Espero que ayude a alguien, mi configuración para lo anterior: (nodejs: 8.4.0, npm: 5.3.0, mocha: 3.3.0)

syberkitten
fuente
0

Mi problema no era devolver la respuesta, por lo que estaba colgando. Si está utilizando express, asegúrese de que res.send (datos), res.json (datos) o cualquier método de API que quiera usar se ejecute para la ruta que está probando.

il0v3d0g
fuente
0

Asegúrese de resolver / rechazar las promesas utilizadas en los casos de prueba, ya sean espías o trozos, asegúrese de que resuelvan / rechacen.

kavigun
fuente