В мокко-тестировании при вызове асинхронной функции, как избежать таймаута Ошибка: превышение тайм-аута в 2000 мс

В моем приложении node я использую mocha для проверки своего кода. При вызове многих асинхронных функций с использованием mocha я получаю ошибку тайм-аута (Error: timeout of 2000ms exceeded.). Как я могу это решить?

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();
        });

    });

});

Ответ 1

Вы можете установить таймаут при выполнении теста:

mocha --timeout 15000

Или вы можете запрограммировать тайм-аут для каждого пакета или каждого теста:

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

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

Для получения дополнительной информации см. документы.

Ответ 2

Я нахожу, что "решение" только увеличения тайм-аутов затушевывает то, что действительно происходит здесь, что является либо

  • Ваш код и/или сетевые вызовы слишком медленные (должно быть до 100 мс для хорошего пользовательского интерфейса).
  • Утверждения (тесты) терпят неудачу, и что-то поглощает ошибки, прежде чем Моча сможет действовать на них.

Обычно вы сталкиваетесь С# 2, когда Mocha не получает ошибок утверждения из обратного вызова. Это вызвано тем, что другой код проглатывает исключение в стеке. Правильный способ справиться с этим - исправить код и не усвоить ошибку.

Когда внешний код проглатывает ваши ошибки

Если это функция библиотеки, которую вы не можете изменить, вам нужно поймать ошибку утверждения и передать ее на Mocha самостоятельно. Вы делаете это, обертывая обратный вызов утверждения в блок try/catch и передавая все исключения обработчику.

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);
    }
  });
});

Этот шаблон можно, конечно, извлечь в какую-то полезную функцию, чтобы сделать тест более приятным для глаз:

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);
    }
}

Ускорение сетевых тестов

Кроме того, я предлагаю вам подобрать совет, чтобы начать использовать тестовые заглушки для сетевых вызовов, чтобы пройти тесты без необходимости полагаться на функционирующую сеть. Используя Mocha, Chai и Sinon, тесты могут выглядеть примерно так.

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;
    });

});

Подробнее см. Sinon nise docs.

Ответ 3

Для меня проблема была на самом деле функцией описания, который при наличии функции стрелки заставляет мокко пропустить тайм-аут и вести себя не последовательно. (С использованием ES6)

поскольку обещание не было отклонено. Я постоянно получал эту ошибку для разных тестов, которые не выполнялись внутри описываемого блока.

так что это выглядит, когда он не работает должным образом:

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

и это работает с использованием анонимной функции

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

Надеюсь, что это поможет кому-то, моя конфигурация для вышеперечисленного: (nodejs: 8.4.0, npm: 5.3.0, mocha: 3.3.0)

Ответ 4

Для асинхронных вызовов нам нужно использовать обратный вызов. Если вы передадите его в(), тогда назовите его также, то есть done(); в противном случае независимо от того, сколько времени вы увеличите, он будет продолжать отсчет времени. В противном случае не передавайте его. Если это не так, и в тестовом примере много обработки, то увеличение значения поможет.