我正在处理混合节点式回调和Bluebird承诺的代码,我需要为它编写一些单元测试。
特别是,cache.js
公开了init()
函数,它与promises一起使用。然后由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-promised,例如: expect(callback).to.eventually.have.been.calledOnce;
重构doSomething()
只是:
function doSomething(callback){ cache.init() .asCallback(回调); }
任何人都可以帮我理解我做错了什么以及如何解决它吗?
答案 0 :(得分:0)
控制台日志不按顺序
日志的顺序正确,因为-(void)textFieldDidChange :(UITextField *)theTextField{
if (panNumber.length <= 5 || panNumber.length > 9) {
[theTextField setKeyboardType:UIKeyboardTypeEmailAddress];
}
else {
[theTextField setKeyboardType: UIKeyboardTypeNumberPad];
}
[theTextField reloadInputViews];
}
将是异步的意思,至少内部控制台会记录Promise
&amp; then
将在下一个刻度线上运行。
至于为什么测试失败是由于几个问题造成的,首先是你似乎没有正确配置catch
,或者至多你的sinon-chai
断言是&n& #39; t kicking in。只是为了确认,测试文件的顶部应该是这样的:
calledOnce
如果你有这个并且它仍然无法正常工作那么可能值得在const chai = require("chai");
const sinonChai = require("sinon-chai");
chai.use(sinonChai);
lib上打开一个问题,但是,一个简单的解决方法是切换到sinon assertions,例如
sinon-chai
其次,当你最终解决这个问题时,你可能会发现测试现在每次都会失败。原因是您在测试中遇到了与日志记录相同的问题 - 在内部承诺有机会解决之前您的断言。最简单的解决方法是使用Mocha的sinon.assert.calledOnce(callback)
处理程序作为断言
done
换句话说,如果mockCache.expects('init').resolves({});
doSomething(() => done());
被调用,那么您就知道已经调用了回调:)
答案 1 :(得分:0)
关注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);
}
});
});