Mongoose:我如何避免回调地狱,同时允许对不返回承诺的 mongoose 方法进行存根?
Posted
技术标签:
【中文标题】Mongoose:我如何避免回调地狱,同时允许对不返回承诺的 mongoose 方法进行存根?【英文标题】:Mongoose: How do I avoid callback hell whilst allowing for stubbing of mongoose methods that do not return promises? 【发布时间】:2018-09-20 01:12:02 【问题描述】:在我用 typescript 编写的 express 节点应用程序中,我正在使用 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
参数,我不知道如何解决存根中的承诺。
有没有一种方法可以使上述工作,或者我可以如何重构我的代码以避免回调地狱,这样我就可以在单元测试中存根猫鼬函数?
【问题讨论】:
【参考方案1】:关于返回的承诺,模型count
方法似乎存在误解(猫鼬很容易理解)。如果在没有回调的情况下调用它会返回一个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 保持不变,那么测试应该继续通过。
也就是说,如果您真的想将模型计数/执行存根,那么类似以下的方法可能会起作用(此处为伪编码):
sinon.stub(MyModel, 'count').returns(
exec() return Promise.resolve(1);
);
希望这能消除一些可能的困惑并有所帮助!
【讨论】:
谢谢 Jason,我缺少的是exec()
函数!关于您关于测试的观点,不确定我是否关注您。如果不存根调用集成点的函数,如何测试父函数返回预期值?
有时它是一条模糊的线,也是 DI 发挥作用以缓解其中一些问题的来源。当一个函数包括访问外部资源时,我将尝试确保访问外部资源之前和之后的任何逻辑都位于易于单元测试的单独函数中,然后对组合函数使用功能测试,该组合函数将前/后逻辑与外部请求。这样做的原因是与使用任何 3rd 方库类似,假设(并希望经过审查)通过 3rd 方库的 API 公开的功能已经被覆盖。
@RichBrowne 很高兴为您提供帮助。测试可能会有点令人困惑,特别是如果它是在实施后完成的,因此 TDD 的受欢迎程度显着上升。祝你好运!以上是关于Mongoose:我如何避免回调地狱,同时允许对不返回承诺的 mongoose 方法进行存根?的主要内容,如果未能解决你的问题,请参考以下文章