在用typescript编写的快速节点应用程序中,我使用mongoose并且我试图避免回调地狱,允许在我的mocha / sinon单元测试中对mongoose函数进行存根。
mongoose没有返回承诺(例如Model.count())我将呼叫包裹在一个新的(等待的)承诺中,该承诺在回调中被解析/拒绝,如下所示:
const myModelCount = await new Promise((resolve, reject) => {
MyModel.count({}, (err, count) => {
if (err) {
reject(err);
return;
}
resolve(count);
});
});
这很好但我不知道如何对包含函数进行单元测试,并避免因未解决的承诺而导致超时错误。我想存根MyModel.count
以便它不会尝试调用数据库,但是如何将其存根以便等待的承诺得到解决并且程序继续?
做类似的事情:
sinon.stub(MyModel, 'count').returns(Promise.resolve(1));
不起作用,因为它无法解决正在等待的承诺,因为我无法访问resolve
/ reject
参数,所以我不知道如何解决存根中的承诺。
有没有办法可以完成上述工作,或者我如何重构代码以避免回调地狱,以便我可以在单元测试中删除mongoose函数?
答案 0 :(得分:1)
关于返回的承诺,使用模型count
方法似乎存在误解(容易与mongoose一起使用)。如果在没有回调的情况下调用它会返回query object,并且与所有查询对象一样,当exec()
调用时(也没有回调)将返回一个promise。
mongoose.Promise = global.Promise; // This sets the mongoose internal Promise to the native Promise, while it is not necessary it is highly advised.
const promise = MyModel.count().exec();
就测试而言,如果单元测试是为了测试一个包装器函数只是调用包装函数,那么我发现这更像是一个功能测试,因为任何测试都应该只关注输入/输出一个函数(函数的API)而不是内部工作(函数的实现)。换句话说,函数应该是任何测试的黑盒子,这样如果实现要改变但API保持不变,那么测试应该继续通过。
那说如果你真的想要将模型数/ exec存根,那么类似下面的东西可能会起作用(这里是伪编码):
sinon.stub(MyModel, 'count').returns({
exec() { return Promise.resolve(1); }
});
希望这可以解决一些可能的困惑并提供帮助!