javascript - 断言 sinon 中的递归调用次数

标签 javascript node.js mocha.js sinon

我有以下通过 promise 递归运行的队列消费者类:

"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() 但根本不起作用(测试似乎没有等待,消费者类中的超时未触发);

预期行为:callCountNUM_OF_ITEMS(通过递归调用)。 实际行为:callCount 始终为 1。

最佳答案

您好,要理解您的队列类在做什么有点令人困惑。是单例吗?

如果它不是一个单例,您的消费者将在构建时使用一个新的空队列进行初始化。

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 构造函数,这样您就知道消费者正在对预期的队列进行操作

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");
        });
        ....

关于javascript - 断言 sinon 中的递归调用次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31585397/

相关文章:

javascript - 如何在 typed.js 中使用 `onComplete()` 方法?

javascript - 从固定元素获取(静态)偏移量

node.js - NodeJS 数组推送不起作用

node.js - 手动安装 NPM 包

testing - 为什么 Mocha 测试用例应该是无状态的?

javascript - 如果 URL 后面有查询字符串,则使用 javascript 更改文件扩展名

javascript - jquery.trigger 2.2.1 时为 "e.stopImmediatePropagation is not a function"

angularjs - 连接到 Node REST api 的应用程序被客户防火墙阻止

node.js - Mocha 之前和之后的钩子(Hook)未执行

javascript - 如何使用 sinon.js 模拟事件处理程序方法?