猫鼬:如何避免回调地狱,同时允许存在不返回承诺的猫鼬方法?

时间:2018-04-10 12:07:22

标签: node.js typescript express mongoose promise

在用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函数?

1 个答案:

答案 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); }
});

希望这可以解决一些可能的困惑并提供帮助!