断言 sinon 中的递归调用次数
Assert number of recursive calls in sinon
我有以下队列消费者class,它通过承诺递归运行:
"use strict";
var queue = require("./queue"),
helpers = require("./helpers"),
vendors = require("../config/vendors"),
queueConf = require("../config/queue");
function Consumer() {
this.queue = new queue.TaskQueue();
this.currentItem = null;
this.port = null;
this.payload = null;
}
Consumer.prototype.payloadSuccessCb = function (data) {
this.payload = data;
this.run();
};
Consumer.prototype.failureCb = function (data) {
console.error(data);
throw new Error(data);
//TODO: Continue queue processing despite the error
};
Consumer.prototype.processItem = function (data) {
this.currentItem = data;
process.send("Proccess " + process.pid + " is processing item " + this.currentItem);
helpers.getPayload(this.currentItem).then(this.payloadSuccessCb, this.failureCb);
};
Consumer.prototype.wait = function () {
var self = this;
process.send("Proccess " + process.pid + " is waiting for new items");
setTimeout(function () {
self.run();
}, queueConf.waitTime);
};
Consumer.prototype.queueSuccessFb = function (data) {
console.error("here");
if (data) {
this.processItem(data);
} else {
this.wait();
}
};
Consumer.prototype.run = function () {
//this.port = helpers.getVendorPortById(this.currentItem);
this.queue.pop().then(this.queueSuccessFb, this.failureCb);
};
exports.Consumer = Consumer;
我已经定义了一个测试,它基本上断言正确的工作流正在发生,并且消费者最终处理队列中的所有任务(这是在真正的 Redis 代理前面工作的集成测试)
测试:
"use strict";
var consumer = require("./../../src/consumer"),
queue = require("./../../src/queue"),
Q = require("Q"),
sinon = require("sinon"),
assert = require("assert"),
queueConf = require("./../../config/queue"),
NUM_OF_ITEMS = 5,
queueInstance,
spy,
consumerInstance;
describe("consumer", function () {
beforeEach(function () {
queueInstance = new queue.TaskQueue();
});
describe("waiting for tasks while the queue is empty", function () {
describe("queue success call back", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
it("should call the success callback once per the defined period", function (done) {
consumerInstance.run();
setTimeout(function () {
sinon.assert.calledOnce(spy);
done();
}, queueConf.waitTime);
});
it("should call the success callback twice per the defined period + 1", function (done) {
consumerInstance.run();
setTimeout(function () {
sinon.assert.calledTwice(spy);
done();
}, queueConf.waitTime * 2);
});
});
describe("wait function", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "wait");
});
});
});
describe("task handling", function () {
beforeEach(function (done) {
this.timeout(6000);
var i, promises = [];
queueInstance = new queue.TaskQueue();
for (i = 1; i <= NUM_OF_ITEMS; i += 1) {
promises.push(queueInstance.push(i));
}
Q.all(promises).then(function () {
done();
});
});
afterEach(function () {
queueInstance.empty();
});
describe("sucess callback", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
it("should run all of the available tasks one by one", function (done) {
this.timeout(6000);
consumerInstance.run();
setTimeout(function () {
console.info(spy.callCount);
assert(spy.callCount === NUM_OF_ITEMS);
done();
}, 2000);
});
});
});
});
我的问题是调用计数总是等于 1。
起初我以为需要调用 andCallThrough()
方法,类似于 Jasmine 中的工作方式,但后来发现正在调用实际函数。
尝试使用 sinon.useFakeTimers()
但根本不起作用(测试似乎没有等待,消费者超时 class 没有触发);
预期行为:callCount
与 NUM_OF_ITEMS
相同(通过递归调用)。
实际行为:callCount
始终为 1。
您好,有点难以理解您的队列 class 在做什么。是单例吗?
如果它是 不是 一个单例,您的消费者将在构造时使用一个新的空队列进行初始化。
function Consumer() {
this.queue = new queue.TaskQueue();
...
}
...
describe("success callback", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
....
这与您在
中创建的队列不同
describe("task handling", function () {
beforeEach(function (done) {
...
queueInstance = new queue.TaskQueue();
...
});
...
因为队列 不 相同 spy.callCount !== NUM_OF_ITEMS
当然除非是单例,即:
new queue.TaskQueue() === new queue.TaskQueue();
我的建议是使 TaskQueue 能够提供给 Consumer 构造函数,这样您就知道 Consumer 正在对预期的队列进行操作
function Consumer(queue) {
this.queue = queue;
...
}
describe("task handling", function () {
beforeEach(function (done) {
...
this.queueInstance = new queue.TaskQueue();
...
});
...
describe("success callback", function () {
before(function () {
consumerInstance = new consumer.Consumer(this.queueInstance);
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
....
我有以下队列消费者class,它通过承诺递归运行:
"use strict";
var queue = require("./queue"),
helpers = require("./helpers"),
vendors = require("../config/vendors"),
queueConf = require("../config/queue");
function Consumer() {
this.queue = new queue.TaskQueue();
this.currentItem = null;
this.port = null;
this.payload = null;
}
Consumer.prototype.payloadSuccessCb = function (data) {
this.payload = data;
this.run();
};
Consumer.prototype.failureCb = function (data) {
console.error(data);
throw new Error(data);
//TODO: Continue queue processing despite the error
};
Consumer.prototype.processItem = function (data) {
this.currentItem = data;
process.send("Proccess " + process.pid + " is processing item " + this.currentItem);
helpers.getPayload(this.currentItem).then(this.payloadSuccessCb, this.failureCb);
};
Consumer.prototype.wait = function () {
var self = this;
process.send("Proccess " + process.pid + " is waiting for new items");
setTimeout(function () {
self.run();
}, queueConf.waitTime);
};
Consumer.prototype.queueSuccessFb = function (data) {
console.error("here");
if (data) {
this.processItem(data);
} else {
this.wait();
}
};
Consumer.prototype.run = function () {
//this.port = helpers.getVendorPortById(this.currentItem);
this.queue.pop().then(this.queueSuccessFb, this.failureCb);
};
exports.Consumer = Consumer;
我已经定义了一个测试,它基本上断言正确的工作流正在发生,并且消费者最终处理队列中的所有任务(这是在真正的 Redis 代理前面工作的集成测试)
测试:
"use strict";
var consumer = require("./../../src/consumer"),
queue = require("./../../src/queue"),
Q = require("Q"),
sinon = require("sinon"),
assert = require("assert"),
queueConf = require("./../../config/queue"),
NUM_OF_ITEMS = 5,
queueInstance,
spy,
consumerInstance;
describe("consumer", function () {
beforeEach(function () {
queueInstance = new queue.TaskQueue();
});
describe("waiting for tasks while the queue is empty", function () {
describe("queue success call back", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
it("should call the success callback once per the defined period", function (done) {
consumerInstance.run();
setTimeout(function () {
sinon.assert.calledOnce(spy);
done();
}, queueConf.waitTime);
});
it("should call the success callback twice per the defined period + 1", function (done) {
consumerInstance.run();
setTimeout(function () {
sinon.assert.calledTwice(spy);
done();
}, queueConf.waitTime * 2);
});
});
describe("wait function", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "wait");
});
});
});
describe("task handling", function () {
beforeEach(function (done) {
this.timeout(6000);
var i, promises = [];
queueInstance = new queue.TaskQueue();
for (i = 1; i <= NUM_OF_ITEMS; i += 1) {
promises.push(queueInstance.push(i));
}
Q.all(promises).then(function () {
done();
});
});
afterEach(function () {
queueInstance.empty();
});
describe("sucess callback", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
it("should run all of the available tasks one by one", function (done) {
this.timeout(6000);
consumerInstance.run();
setTimeout(function () {
console.info(spy.callCount);
assert(spy.callCount === NUM_OF_ITEMS);
done();
}, 2000);
});
});
});
});
我的问题是调用计数总是等于 1。
起初我以为需要调用 andCallThrough()
方法,类似于 Jasmine 中的工作方式,但后来发现正在调用实际函数。
尝试使用 sinon.useFakeTimers()
但根本不起作用(测试似乎没有等待,消费者超时 class 没有触发);
预期行为:callCount
与 NUM_OF_ITEMS
相同(通过递归调用)。
实际行为:callCount
始终为 1。
您好,有点难以理解您的队列 class 在做什么。是单例吗?
如果它是 不是 一个单例,您的消费者将在构造时使用一个新的空队列进行初始化。
function Consumer() {
this.queue = new queue.TaskQueue();
...
}
...
describe("success callback", function () {
before(function () {
consumerInstance = new consumer.Consumer();
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
....
这与您在
中创建的队列不同describe("task handling", function () {
beforeEach(function (done) {
...
queueInstance = new queue.TaskQueue();
...
});
...
因为队列 不 相同 spy.callCount !== NUM_OF_ITEMS
当然除非是单例,即:
new queue.TaskQueue() === new queue.TaskQueue();
我的建议是使 TaskQueue 能够提供给 Consumer 构造函数,这样您就知道 Consumer 正在对预期的队列进行操作
function Consumer(queue) {
this.queue = queue;
...
}
describe("task handling", function () {
beforeEach(function (done) {
...
this.queueInstance = new queue.TaskQueue();
...
});
...
describe("success callback", function () {
before(function () {
consumerInstance = new consumer.Consumer(this.queueInstance);
spy = sinon.spy(consumerInstance, "queueSuccessFb");
});
....