Тестовый обратный вызов в конце цепочки обещаний
Я имею дело с обратными вызовами в стиле смешивания кода и обещаниями Bluebird, и мне нужно написать несколько тестов для этого.
Особенно, cache.js
подвергает init()
функция, которая работает с обещаниями. Затем он вызывается doSomething()
функция в другом файле (например, index.js
) который в свою очередь принимает обратный вызов, который должен быть вызван в конце init()
,
Псевдокод выглядит следующим образом:
// [ cache.js ]
function init() {
return performInitialisation()
.then((result) => return result);
}
// [ index.js ]
var cache = require('./cache');
function doSomething(callback) {
console.log('Enter');
cache.init()
.then(() => {
console.log('Invoking callback');
callback(null);
})
.catch((err) => {
console.log('Invoking callback with error');
callback(err);
});
console.log('Exit');
}
Возможный модульный тест может быть (показывая только соответствующий код):
// [ index.test.js ]
...
var mockCache = sinon.mock(cache);
...
it('calls the callback on success', function(done) {
mockCache.expects('init')
.resolves({});
var callback = sinon.spy();
doSomething(callback);
expect(callback).to.have.been.calledOnce;
done();
});
Этот тест проходит, однако изменяет ожидание на not.have.been.calledOnce
также проходит, что неправильно.
Кроме того, консольные журналы не в порядке:
Enter
Exit
Invoking callback
Я рассмотрел несколько возможностей, ни одна из которых не сработала:
Использование chai-as-обещано, например
expect(callback).to.eventually.have.been.calledOnce;
Рефакторинг
doSomething()
быть просто:function doSomething (callback) {cache.init ().asCallback (callback); }
Может кто-нибудь помочь мне понять, что я делаю неправильно, и как я могу это исправить, пожалуйста?
2 ответа
журналы консоли не в порядке
Журналы в правильном порядке, потому что ваш Promise
будет асинхронным, то есть внутренняя консоль будет регистрировать вызовы then
& catch
будет работать на следующем тике.
Относительно того, почему тест не пройден, является результатом нескольких проблем, во-первых, у вас, похоже, нет sinon-chai
настроен правильно, или в лучшем случае ваш calledOnce
утверждение не включается. Просто для подтверждения, верхняя часть вашего тестового файла должна выглядеть примерно так:
const chai = require("chai");
const sinonChai = require("sinon-chai");
chai.use(sinonChai);
Если у вас это есть, но оно все еще не работает должным образом, возможно, стоит открыть sinon-chai
lib, однако, простой обходной путь состоит в том, чтобы перейти к утверждениям sinon, например:
sinon.assert.calledOnce(callback)
Во-вторых, когда вы в конце концов исправите это, вы, вероятно, обнаружите, что тест теперь не будет выполнен... каждый раз. Причина в том, что в вашем тесте возникла та же проблема, что и при ведении журнала - ваше утверждение до того, как внутреннее обещание успело решить. Самый простой способ исправить это на самом деле с помощью вашего done
обработчик из мокко, как ваше утверждение
mockCache.expects('init').resolves({});
doSomething(() => done());
Другими словами, если done
получить вызов, то вы знаете, что обратный вызов был вызван:)
После комментария James я пересмотрел свои тесты следующим образом:
it('calls the callback on success', function(done) {
mockCache.expects('init')
.resolves({});
doSomething(done);
});
it('calls the callback on error', function(done) {
mockCache.expects('init')
.rejects('Error');
doSomething((err) => {
if (err === 'Error') {
done();
} else {
done(err);
}
});
});