![](/img/trans.png)
[英]How can I traverse an promise object reference chain synchronously in a loop
[英]How can I stub a Promise such that my test can be run synchronously?
我試圖通過對其中一個依賴項(在本例中為UserManager
進行存根來對模塊進行單元測試
該模塊的簡化版本如下:
// CodeHandler
module.exports = function(UserManager) {
return {
oAuthCallback: function(req, res) {
var incomingCode = req.query.code;
var clientKey = req.query.key;
UserManager.saveCode(clientKey, incomingCode)
.then(function(){
res.redirect('https://test.tes');
}).catch(function(err){
res.redirect('back');
}
);
}
};
};
我捻熄的UserManager的saveCode
它返回一個函數Promise
,使得它返回一個解決的承諾,但是當我assert
這res.redirect
被調用,唉,在斷言的時間res.redirect
尚未被調用。
單元測試的簡化版本是:
// test
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var res = {
redirect: function() {}
};
var expectedUrl = 'https://test.tes';
var ch;
beforeEach(function() {
sinon.stub(UserManager, 'saveCode').returns(
new RSVP.Promise(function(resolve, reject){
resolve();
})
);
sinon.stub(res, 'redirect');
ch = CodeHandler(UserManager);
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
});
如何正確地保留承諾,以便被測方法同步運行?
我已經使用sinon-stub-promise
制定了一個解決方案。
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var ch;
var promise;
var res = {
redirect: function() {}
};
beforeEach(function() {
promise = sinon.stub(UserManager, 'saveCode').returnsPromise();
ch = CodeHandler(UserManager);
sinon.stub(res, 'redirect');
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
describe('can save code', function() {
var expectedUrl = 'https://test.tes';
beforeEach(function() {
promise.resolves();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
});
});
describe('can not save code', function() {
var expectedUrl = 'back';
beforeEach(function() {
promise.rejects();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
})
});
這非常有效。
好吧,最簡單的事情就是不要將它存根同步運行,因為這可能會改變執行順序並使用Mocha內置的promises支持(如果使用jasmine則使用jasmine-as-promised)。
原因是可能會出現以下情況:
somePromise.then(function(){
doB();
});
doA();
如果你使promises同步解決執行順序 - 從而輸出程序發生變化,使測試變得毫無價值。
相反,您可以使用測試語法:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () => {
return methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
});
});
您可以為單行使用更輕的箭頭語法,這使得測試更簡潔:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () =>
methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
);
});
在RSVP中,你無法設置調度程序,因此無論如何都不可能同步測試事物,像bluebird這樣的其他庫允許你自己承擔風險,但即使在允許你這樣做的庫中它也可能不是最好的主意。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.