我有一个如下所示的功能:
function test(parms) {
var self = this;
return this.test2(parms)
.then(function (data) {
if (data) {
return ;
}
else {
return Bluebird.delay(1000)
.then(self.test.bind(self, parms));
}
}.bind(self));
};
我正在尝试为此功能编写单元测试。我使用sinon.stub
来模拟函数test2
的功能。
我编写了一个测试用例,其中test2
返回true
,因此test
函数成功完成执行。但是我想要一个测试用例,其中第一个实例test2
返回false
,它等待延迟,下次test2
返回true
。为此我写了我的测试用例如下:
var clock;
var result;
var test2stub;
var count = 0;
before(function () {
clock = sinon.useFakeTimers();
//object is defined before
test2stub = sinon.stub(object,"test2", function () {
console.log("Count is: " + count);
if (count === 0) {
return (Bluebird.resolve(false));
}
else if (count === 1) {
return (Bluebird.resolve(true));
}
});
clock.tick(1000);
object.test("xyz")
.then(function (data) {
result = data;
});
clock.tick(1000);
count = count + 1;
clock.tick(1000);
});
after(function () {
test2stub.restore();
clock.restore();
});
it("result should be undefined. Check if test2 returned false first & true next",
function () {
expect(result).to.be.undefined;
});
在日志中显示count只有值0。
答案 0 :(得分:2)
test
的代码实际上是不正确的。它永远不会返回成功的数据。它返回undefined
。该函数应返回成功数据,否则您将无法将其用作下一个.then
处理程序的参数
.then(function (data) {
if (data) {
return data;
}
接下来,您对函数test
做出了错误的假设。它永远不会返回undefined
。该函数相当危险,并且会在无限的承诺链中永远调用自己,直到它从test2
中挤出任何非空数据。
我们不应该在before
或beforeEach
部分启动测试代码。 before
和after
旨在为假冒计时器准备环境,然后进行恢复
在it
处理程序中调用测试代码的一个原因是因为promises应该以不同方式处理。处理程序应接受一个参数,该参数指示测试将是异步的,并且测试引擎会给它一个超时(通常为10秒)来完成。测试期望调用done()
以指示测试成功,或者调用done(error)
如果失败并且有error
个对象(或expect
引发异常)。<登记/>
此外,您应该在异步操作开始后移动假计时器。实际上,在您的代码中,第一个clock.tick
是无用的。
使用fakeTimers
有一个技巧。您可以手动移动时间,但它不会自行移动。对于第一个滴答,它运作良好。承诺被执行。但是在返回.delay(1000)
承诺时,将没有命令来推动时间。因此,要正确完成测试(不修改测试代码),您还必须存根Bluebird.delay
我会更改存根实现并执行类似这样的操作
describe("test2", function(){
beforeEach(function(){
clock = sinon.useFakeTimers();
test2stub = sinon.stub(object,"test2", function () {
console.log("Count is: " + count);
return (Bluebird.resolve((count++) > 0));
});
var _delay = Bluebird.delay.bind(Bluebird);
bluebirdDelayStub = sinon.stub(Bluebird,"delay", function (delay) {
var promise = _delay(delay);
clock.tick(1000);
return promise;
});
})
it("should eventually return true", function (done) {
object.test("xyz")
.then(function (data) {
expect(data).to.be.true;
expect(count).to.equal(2);
done();
})
.catch(function(err){
done(err);
});
clock.tick(1000);
});
after(function () {
test2stub.restore();
clock.restore();
bluebirdDelayStub.restore();
});
})
PS我在Node.js 0.10.35和Bluebird 2.9.34下验证了这段代码