【问题标题】:Testing Restify Route Handler that contains Promise Code Block, using SinonJs and Mocha使用 SinonJs 和 Mocha 测试包含 Promise 代码块的 Restify Route Handler
【发布时间】:2015-11-27 05:23:30
【问题描述】:

我在下面有一个 restify 操作代码块:

function retriveAll(req, res, next) {
        db.user
        .find({where: {id: 1})
        .then(function(user){
            res.send(user);
        })
        .catch(function(details){
            res.send(details.message);
        })
        .finally(function(){
            next();
        });
    }

我想测试这个动作,专门验证 res.send() 是在这个代码块中调用的。稍后验证 res.send() 返回的数据。我正在使用 SinonJsMocha 来测试框架。这是上述方法的示例测试代码块。

describe('retrieveAll()', function() {

    reqStub = {};
    resStub = {send: sinon.stub()};
    nextStub = sinon.stub();

    beforeEach(function() {
        module.retrieveAll(reqStub, resStub, nextStub);
    });

    // this doesn't work
    // and the sub.calledCount is 0
    // i wonder if it's because the res.send() is inside a Promise code block???
    // if I move the res.send() out from Promise, just before next(), then it works
    it('should call res.send()', function() {
        sinon.assert.calledOnce(resStub.send);
    });

    // this one works
    it('should call next', function() {
        sinon.assert.calledOnce(nextStub);
    });
});

有人能解释一下吗?

【问题讨论】:

    标签: node.js promise bluebird sinon restify


    【解决方案1】:

    所以,感谢 @Amit 将我指向beforeEach 上的done 回调

    首先,我修改了retrieveAll,因此next 回调包含在承诺链中。我把它放在finally 处理程序中,确保在所有进程之后都会调用next

    第二,我将done 传递给beforeEach,然后nextStub 将监视done 回调。

    第三,我没有将done cb 传递给module.v1.retrieveAll,而是使用了nextStub。这解决了测试nextStub.calledOnce的问题。

    更新后的代码现在看起来:

    function retriveAll(req, res, next) {
            db.user
            .find({where: {id: 1})
            .then(function(user){
                res.send(user);
            })
            .catch(function(details){
                res.send(details.message);
            })
            .finally(function(){
                next();
            });
        }
    
    describe('retrieveAll()', function() {
    
        var reqStub = {};
        var resStub = {send: sinon.stub()};
        var nextStub;
    
        beforeEach(function(done) {
            nextStub = sinon.spy(done);
            module.retrieveAll(reqStub, resStub, nextStub);
        });
    
        // this doesn't work
        // and the sub.calledCount is 0
        // i wonder if it's because the res.send() is inside a Promise code block???
        // if I move the res.send() out from Promise, just before next(), then it works
        it('should call res.send()', function() {
            sinon.assert.calledOnce(resStub.send);
        });
    
        // this one works
        it('should call next', function() {
            sinon.assert.calledOnce(nextStub);
        });
    });
    

    我将选择@Amit 答案作为最佳答案,因为他提供了帮助并为我提供了有关更改的线索。

    【讨论】:

    • 看起来测试和我的答案完全一样(除了你的错字,nextStubnextSpy,但你的两者都有),retriveAll 是根据什么在我的cmets上,是这样吗,还是最后有什么其他的?
    • @amit,我已经更正了 nextStubnextSpy。是的,这与您的答案相同,只是为了解决nextStub 问题而进行了一些更改。这个答案是为了显示对我的原始代码的修改。 tnx
    • 酷。很高兴能帮上忙。
    【解决方案2】:

    beforeEach() 的回调函数接收一个done 参数,可以调用该参数来表示异步完成。由于您的 retriveAll 函数调用最后一个参数 (next) 作为最后一个操作,您可以将该参数作为 next 值传递,它应该可以工作:

    beforeEach(function(done) {
        module.retrieveAll(reqStub, resStub, done);
    });
    

    但是,您将失去nextStub,所以...或者,您可以窥探 done 函数:

    describe('retrieveAll()', function() {
    
        var reqStub = {};
        var resStub = {send: sinon.stub()};
        var nextSpy;
    
        beforeEach(function(done) {
            nextSpy = sinon.spy(done);
            module.retrieveAll(reqStub, resStub, done);
        });
    
        // this doesn't work
        // and the sub.calledCount is 0
        // i wonder if it's because the res.send() is inside a Promise code block???
        // if I move the res.send() out from Promise, just before next(), then it works
        it('should call res.send()', function() {
            sinon.assert.calledOnce(resStub.send);
        });
    
        // this one works
        it('should call next', function() {
            sinon.assert.calledOnce(nextSpy);
        });
    });
    

    【讨论】:

    • 感谢@Amit 的回复。我已经应用了你的建议,不幸的是它仍然给出了同样的错误。 AssertError: expected stub to be called once but was called 0 times
    • 哦,是的.. 刚刚注意到,你不是说sinon.assert.calledOnce(re S Stub.send);吗?
    • 另外,nextStub 测试受到影响,现在出现同样的错误。
    • 最后一条评论不清楚。你现在的状态是什么?
    • 我修改了我的问题以反映更正,再次尝试但没有运气。当前状态:sinon.assert.calledOnce(nextSpy); 现在也给出错误或失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-08
    • 2015-12-01
    • 1970-01-01
    • 2017-03-23
    • 1970-01-01
    • 2015-02-17
    • 2013-02-10
    相关资源
    最近更新 更多