В мокко-тестировании при вызове асинхронной функции, как избежать таймаута Ошибка: превышение тайм-аута в 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(); в противном случае независимо от того, сколько времени вы увеличите, он будет продолжать отсчет времени. В противном случае не передавайте его. Если это не так, и в тестовом примере много обработки, то увеличение значения поможет.