【问题标题】:Sinon - how to stub nested function?Sinon - 如何存根嵌套函数?
【发布时间】:2015-02-12 07:04:43
【问题描述】:

抱歉,如果这是一个简单的问题,我对 Node 和 Sinon 比较陌生。我正在努力弄清楚如何断言在 Nodejs 中调用了嵌套异步函数。

我正在使用 mocha、chai、sinon 和 request (https://github.com/request/request),但我认为我在存根部分缺少一些基本的东西。

my_app.js 中的示例 -

var request = require('request');

function MyModule() {
};

MyModule.prototype.getTicker = function(callback) {
    request('http://example.com/api/ticker', function(error, response) {
        if (error) {
            callback(error);
        } else {
            callback(null, response);
        }
    });
};

exports.mymodule = new MyModule();

测试内部。我正在尝试终止对请求的调用并提供一些要返回的虚拟数据。但是我在创建存根的行上不断收到错误“未定义请求”。

var myApp = require('../my_app.js')
    ,assert = require("assert")
    ,chai = require('chai')
    ,sinon = require('sinon')
    ,expect = chai.expect;

describe('mymodule object', function() {

    var mymodule = myApp.mymodule;

    before(function(done) {
        sinon.stub(request).yields(null, JSON.stringify({
            price: '100 USD'
        }));
        done();
    });

    it('getTicker function should call request on example ticker', function(done) {
        mymodule.getTicker(function(error, result){
            request.called.should.be.equal(true);
            done();
        });
    });

});

我知道我可以分配 sinon.stub(objname, "funcname") 或 sinon.stub("funcname"),但那些只设置外部对象,我试图存根函数内部的函数请求获取代码。

关于如何做到这一点的任何想法?也许我也需要使用间谍(但如何?)或者有更好的方法来测试上面的 getTicker 函数吗?

【问题讨论】:

    标签: node.js request mocha.js sinon chai


    【解决方案1】:

    您收到未定义的消息,因为 request 变量在您的测试范围内是未知的。但是,即使您要更正此问题并将 request 库分配给变量,您仍然会收到错误消息,因为 sinon 需要在任何提供的对象上使用方法才能创建存根。

    这样的结果是request 函数本身不能被存根,因为它不存在于对象上,而是作为定义了其他方法的函数。因此,为了支持可测试性,最好不要直接在代码中使用request,而是使用其附加的方法,然后可以将其存根。例如:

    my_app.js

    MyModule.prototype.getTicker = function(callback) {
      request.get('http://example.com/api/ticker', function(error, response) {
        ...
      });
    };
    

    my_test.js

    var request = require('request');
    
    before(function() {
      sinon.stub(request, 'get').yields(null, JSON.stringify({price: '100 USD'}));
    });
    
    it('getTicker function should call request on example ticker', function() {
      mymodule.getTicker();
      request.get.called.should.be.equal(true);
    });
    

    (请注意,当存根同步时,不需要异步运行 mocha)。

    【讨论】:

    • 好吧太棒了,没想到要在这上面使用get方法。现在我还可以使用间谍来验证回调是否被调用。
    • 啊,是的,我可以验证回调是否被调用。但我使用了一点不同的语法 mymodule.getTicker(callback); request.get.should.have.been.called;request.get.should.have.been.called; 非常感谢!