Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 838
Justin Maat Avatar asked Dec 13 '14 19:12

Justin Maat


1 Answers

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).

like image 77
scarlz Avatar answered Oct 05 '22 06:10

scarlz