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

200

В моем приложении узла я использую мокко для проверки своего кода. При вызове многих асинхронных функций с использованием 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();
        });

    });

});
Сэчин
источник
это интеграционный тест? тесту нужно много времени - может быть, вам стоит подумать о заглушках - github.com/thlorenz/proxyquire может вам помочь.
Суруи
@Surui спасибо, я посмотрю на это
Сачин
Могу ли я порекомендовать использовать обещания для асинхронных вещей и протестировать их, тогда Бай как обещание
Крым

Ответы:

344

Вы можете установить время ожидания при запуске теста:

mocha --timeout 15000

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

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

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

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

Андреас Халтгрен
источник
3
короче версия есть -t. если вы используете mocha-test для запуска mocha из задачи grunt, это также поддерживается в параметре object options:{timeout:15000}.
svassr
5
К вашему сведению: передача функций стрелки в Mocha не рекомендуется. mochajs.org/#arrow-functions
c0ming
4
Функции стрелки не обескуражены в ссылке выше. Это просто говорит о том, что вам просто нужно знать, что они делают, чтобы вы не облажались при необходимости доступа к контексту. Мне никогда не нужен контекст, так как использование тайм-аутов хрупко, и все мои тесты выполняются за несколько мс, но я сталкиваюсь с той же проблемой при использовании sinon-test. Все еще используйте лямбды в 99% случаев.
oligofren
26
TypeError: this.timeout is not a functionпри использовании"mocha": "^3.5.0"
Junior Mayhé
5
@adi вы уверены, что не используете функции стрелок? Что касается async / await, он находится в документации, поэтому должен работать (и то же самое, что и использование обещаний). Звучит как еще один вопрос.
Андреас Халтгрен
80

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

  1. Ваш код и / или сетевые вызовы слишком медленные (должно быть меньше 100 мс для хорошего пользовательского опыта)
  2. Утверждения (тесты) не выполняются, и что-то проглатывает ошибки, прежде чем Mocha сможет их исправить.

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

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

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

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

});

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

oligofren
источник
У меня огромный набор тестов, и я просто выполнил все обещания в своих спецификациях, чтобы убедиться, что они все звонят done()в конце обещания, и я уже высмеиваю сетевые вызовы, используя Angular $httpBackend, но не повезло. Упаковка каждой спецификации с помощью try-catch не кажется прагматичной. Любые другие предложения? Спасибо!
Густаво Матиас
@GustavoMatias Вы на самом деле не упомянули, в чем ваша проблема, просто заявили, что это не решение того, с чем у вас возникли проблемы. Пожалуйста, уточните :-) Не достаточно ли быстро провалились ваши тесты? Они иногда терпят неудачу, но вы хотели бы знать, почему? Трудно догадаться, чего вы намерены достичь.
oligofren
привет @oligofren! это было не лучшее объяснение. Здесь есть более подробное объяснение моей проблемы stackoverflow.com/questions/34510048/… спасибо!
Густаво Матиас
«В общем, самый чистый (но самый уродливый) способ решения этой проблемы - заключить код в код try / catch и передать любые исключения обработчику done». Нет, это совсем не самый чистый способ. Отнюдь не. Самый чистый способ - написать код, который не поглощает исключения. Каждый раз, когда я видел, как кто-то жаловался на то, что Мокко не обнаружил неудавшийся тест, это было из-за того, что что-то проглотило исключение. Добавление try.... catch...работ вокруг ошибка в коде при испытании , а не исправить его.
Луи
@ Луис, возможно, вы правы по поводу того, почему здесь, но я не могу проверить это на ровном месте. в любом случае, у людей есть проблема с тем, что Мокко, похоже , не может уловить какую-то ошибку, и это способ ее устранения. В данном подходе предполагается, что код, поглощающий ошибку, не является какой-либо библиотечной функцией или чем-то подобным, и в этом случае ее не так легко решить.
oligofren
7

Немного поздно, но кто-то может использовать это в будущем ... Вы можете увеличить время ожидания теста, обновив сценарии в вашем package.json следующим образом:

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

Запустите ваши тесты с помощью команды test

Даниэль Мбея
источник
Работал на меня! Спасибо вам!
RayLoveless
5

Если вы используете функции стрелок:

it('should do something', async () => {
  // do your testing
}).timeout(15000)
lukas_o
источник
1

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

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

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

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

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

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

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

syberkitten
источник
0

Моя проблема не отправляла ответ, поэтому он зависал. Если вы используете Express, убедитесь, что res.send (data), res.json (data) или любой другой метод API, который вы хотите использовать, выполняется для маршрута, который вы тестируете.

il0v3d0g
источник
0

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

kavigun
источник