【发布时间】:2016-09-16 16:22:09
【问题描述】:
我希望测试以下函数,其中大量使用了 async.js:
MyClass.prototype.pipeline = function(arg1, arg2) {
...
async.waterfall([
async.apply(self.a.f.bind(self.a), arg1, arg2),
function(data, callback) {
async.each(data, function(d, callback) {
async.waterfall([
async.apply(self.b.f.bind(self.b), d),
self.c.f.bind(self.c),
self.d.f.bind(self.d),
self.e.f.bind(self.f)
], function(err, results) {
if (err) {
...
}
callback();
});
}, function(err) {
callback(err, data);
});
}
], function (err, result) {
...
});
};
现在我知道我可以将这里发生的很多事情分开来分开函数,但它是一个流线型操作的管道,在前一个完成后彼此传递数据,所以我希望保持这样的状态而不是示例将函数 function(data, callback) {...} 与名称类似 BCDEpipeline 分开。
无论如何,我的问题是我基于第一个async.waterfall() done 函数的 done 回调做了一些断言,问题是它被稍后调用(延迟)即使我已经存根了 a、b、c、d 和 e 函数并且使他们立即产生下一个回调。请注意,我不能只存根 async.waterfall() 并使其产生完成回调,因为我将留下未经测试的代码的关键分支(async.each() 和第二个 async.waterfall() 的内部完成回调。
在像这样调用MyClass.prototype.pipeline() 函数后,我尝试使用 sinon 假计时器并使用this.clock.tick(0);:
var obj = new MyClass();
obj.pipeline(5, 3);
this.clock.tick(0);
/* assertions */
...
但即便如此,断言部分还是在调用任何完成函数之前执行的。我试图深入研究异步库代码,看看它是如何调用它的完成函数的仍然是先执行。
如果我使用一些嵌套的 setImmediate() 调用它工作正常,但这是这个问题最糟糕的解决方案。
【问题讨论】:
-
.bind的全部用途是什么?这是您的实际代码还是您正在为这个问题缩短一些内容? -
@clay 我使用 bind 来调用使上下文成为实例本身,这是从不相关部分中剥离出来的代码,你看到的任何地方
...都是不相关的部分。所有的名字都是虚构的(a、b、c、d、e、f、arg1、arg2 等)
标签: javascript node.js unit-testing sinon async.js