Обрезание многообещающей функции с синоном и синей птицей
В файле, который я хотел бы протестировать, у меня есть следующий код:
var httpGet = Promise.promisify(require("request").get);
httpGet(endpoint, {
auth: {bearer: req.body.access_token},
json: true
})
.then(...)
Теперь, в моих тестах, я хочу убедиться, что HTTPGet был вызван один раз и убедитесь, что параметры действительны. Перед тем, как обещать, мой тест выглядит следующим образом:
beforeEach(function () {
request.get = sinon.stub()
.yields(null, null, {error: "test error", error_description: "fake google error."});
});
afterEach(function () {
expect(request.get).to.have.been.calledOnce();
var requestArgs = request.get.args[0];
var uri = requestArgs[0];
expect(uri).to.equal(endpoint);
//...
});
К сожалению, это не работает, когда request.get является многообещающим. Вместо этого я попробовал наследовать request.getAsync(поскольку bluebird добавляет "Async" к многозначным функциям), но это тоже не работает. Любые идеи?
Ответы
Ответ 1
Promise.promisify не изменяет объект, он просто берет функцию и возвращает новую функцию, она полностью не осознает, что функция даже принадлежит "request"
.
"Async"
суффиксные методы добавляются к объекту при использовании promisify All
Promise.promisifyAll(require("request"));
request.getAsync = sinon.stub()
.yields(null, null, {error: "test error", error_description: "fake google error."});
expect(request.getAsync).to.have.been.calledOnce();
Ответ 2
Любой, кто сталкивается с этим. У меня небольшая утилита func
function stubCBForPromisify(stub) {
let cbFn = function() {
let args = [...arguments];
args.shift();
return stub(...args);
};
return cbFn.bind(cbFn, () => ({}));
}
В тесте
var getStub = sinon.stub().yields(null, {error: "test error", error_description: "fake google error."})
sinon.stub(require("request"), 'get', stubCBForPromisify(getStub))
expect(getStub).to.have.been.calledOnce();
Ответ 3
Я столкнулся с проблемой тестирования с использованием tape
и proxyquire
. Я не уверен, какие люди используют шаблоны/рамки, которые позволяют им напрямую изменять объект required
'd request
, как показано в принятом ответе. В моем случае, в файле я хочу проверить я require('jsonFile')
, затем вызовите bluebird.promisifyAll(jsonFile)
. В обычных условиях это создает метод readFileAsync
, который я хочу заглушить. Однако, если во время тестирования я пытаюсь использовать proxyquire
для передачи в заглушку, вызов promisifyAll
перезаписывает мой заглушка.
Я смог исправить это, также обрезая promisifyAll
как no-op. Как показано, это может быть слишком грубым, если вы полагаетесь на некоторые из асинхронных методов, которые должны быть созданы как есть.
core.js
:
var jsonFile = require('jsonfile');
var Promise = require('bluebird');
Promise.promisifyAll(jsonFile);
exports.getFile = function(path) {
// I want to stub this method during tests. It is
// created by promisifyAll
return jsonFile.readFileAsync(path);
}
core-test.js
:
var proxyquire = require('proxyquire');
var tape = require('tape');
var sinon = require('sinon');
require('sinon-as-promised');
tape('stub readFileAsync', function(t) {
var core = proxyquire('./core', {
'jsonfile': {
readFileAsync: sinon.stub().resolves({})
},
'bluebird': { promisifyAll: function() {} }
});
// Now core.getFile() will use my stubbed function, and it
// won't be overwritten by promisifyAll.
});