每次调用时将 sinon 中的函数存入 return 不同的值
Stubbing a function in sinon to return different value every time it is called
我有一个函数如下图:
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
returns true
因此 test
函数成功完成执行。但是我想要一个测试用例,其中第一个 test2
returns false
,它等待延迟,下一次 test2
returns 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。
test
的代码其实是错误的。它从来没有 return 成功的数据。它 returns undefined
。该函数应该 return 成功数据,否则您将无法将它用作下一个 .then
处理程序
的参数
.then(function (data) {
if (data) {
return data;
}
接下来你对函数做出了错误的假设test
。它永远不会 return undefined
。该函数相当危险,它将在无尽的承诺链中永远调用自己,直到它从 test2
中挤出任何非空数据。
不应在 before
或 beforeEach
部分启动测试代码。 before
和 after
是为了像伪造计时器一样准备环境然后恢复它们。
在 it
处理程序中调用测试代码的一个原因是因为承诺应该以不同的方式处理。处理程序应接受一个参数,该参数指示测试将是异步的,并且测试引擎会为其提供超时(通常为 10 秒)以完成。预计测试将调用 done()
以指示测试成功或调用 done(error)
如果它失败并且存在 error
对象(或 expect
抛出异常)。
您还应该在 异步操作开始后移动假计时器 。在您的代码中实际上第一个 clock.tick
是无用的。
使用 fakeTimers
有一个技巧。您可以手动移动时间,但它不会自行移动。对于第一个滴答声,它运作良好。承诺得到执行。然而,根据returning .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
下验证了这段代码
我有一个函数如下图:
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
returns true
因此 test
函数成功完成执行。但是我想要一个测试用例,其中第一个 test2
returns false
,它等待延迟,下一次 test2
returns 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。
的参数test
的代码其实是错误的。它从来没有 return 成功的数据。它 returnsundefined
。该函数应该 return 成功数据,否则您将无法将它用作下一个.then
处理程序.then(function (data) { if (data) { return data; }
接下来你对函数做出了错误的假设
test
。它永远不会 returnundefined
。该函数相当危险,它将在无尽的承诺链中永远调用自己,直到它从test2
中挤出任何非空数据。不应在
before
或beforeEach
部分启动测试代码。before
和after
是为了像伪造计时器一样准备环境然后恢复它们。
在it
处理程序中调用测试代码的一个原因是因为承诺应该以不同的方式处理。处理程序应接受一个参数,该参数指示测试将是异步的,并且测试引擎会为其提供超时(通常为 10 秒)以完成。预计测试将调用done()
以指示测试成功或调用done(error)
如果它失败并且存在error
对象(或expect
抛出异常)。
您还应该在 异步操作开始后移动假计时器 。在您的代码中实际上第一个clock.tick
是无用的。使用
fakeTimers
有一个技巧。您可以手动移动时间,但它不会自行移动。对于第一个滴答声,它运作良好。承诺得到执行。然而,根据returning.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
下验证了这段代码