Sinon – how to stub nested function?

Apologies if this is a simple question, I’m relatively new to Node and Sinon. I’m struggling trying to figure out how to assert that a nested asynchronous function was called in Nodejs.

I’m using mocha, chai, sinon, and request (https://github.com/request/request) but think I’m missing something basic on the stubbing part.

Example inside 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();

Inside the test. I’m trying to stub out the call to request and provide some dummy data to return. But I keep getting an error “request is not defined” on the line where I”m creating the stub.

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();
        });
    });

});

I know I can assign sinon.stub(objname, “funcname”) or sinon.stub(“funcname”), but those only set the outer object , I’m trying to stub the function request which is inside the function getTicker.

Any ideas on how to do this? Maybe I need to use a spy as well (but how?) Or is there a better approach to test the above getTicker function?

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

You are receiving the undefined message because the request variable is unknown within the scope of your test. However, even if you were to correct this and assign the request library to the variable, you would still receive an error as sinon requires a method on any provided object in order to create a stub.

The consequence of such is that the request function itself cannot be stubbed as it does not exist on an object but as a function onto which other methods are defined. In order to support testability, therefore, it’d be preferable to forgo using request directly in your code, and instead use its attached methods which can then be stubbed. For example:

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

(Note that running mocha asynchronously is un-necessary when a stub is synchronous).

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply