Mock the results of an asynchronous call

3,373 views
Skip to first unread message

Philip Schweiger

unread,
May 18, 2011, 6:04:30 PM5/18/11
to Sinon.JS
Hi,

This can be a general-application question, but I'll start with my
specific use case. I'm working on a wrapper around the Facebook API,
but rather than actually making a bunch of calls to Facebook, I'm
trying to use sinon to stub/mock the FB API.

I'm getting stuck on how to stub responses within asynchronous
functions, though. For example, I have a function that calls

FB.getLoginStatus

This function takes a callback, so for example if I were just calling
it directly, it would look like so:

FB.getLoginStatus(function(response){
//do something
});

That response will be one of three values - unknown, connected,
notConnected (actually a whole object, but I'm simplifying for the
sake of illustration).

What I'm trying to do is write a wrapper that calls this function and
responses appropriately to three states, so I tried, for instance:

var stub = sinon.stub(FB,'getLoginStatus').returns('connected');

That doesn't work, though, as "connected" is never passed to the inner
callback function (the "response" parameter). Any insight would be
appreciated!

Thanks,

Philip

Philip Schweiger

unread,
May 18, 2011, 6:29:37 PM5/18/11
to Sinon.JS
I believe I may have figured this out, but would appreciate any notes
if there is a better way to go about this. I set up a stub, like so:

var getLoginStatus = sinon.stub(
FB,
'getLoginStatus',
function(callback){
callback({status:'unknown'});
}
);

I am using qunit as my testing framework, so then I would go ahead and
call my wrapper and then my assertion, then for the next test I just
change getLoginStatus.

EG, in pseudo-code:

var getLoginStatus = sinon.stub(
FB,
'getLoginStatus',
function(callback){
callback({status:'unknown'});
}
);

mywrapper();

ok(expected result from status unknown):

getLoginStatus = sinon.stub(
FB,
'getLoginStatus',
function(callback){
callback({status:'connected'});
}
);

ok(expected result from status connected);

and so forth.

Thomas Meyer

unread,
May 19, 2011, 5:49:47 AM5/19/11
to sin...@googlegroups.com
There are special stub functions for this:
var stub = sinon.stub(FB,'getLoginStatus').callsArgWith(0, {status:'unknown'});

Or as of version 1.1.1 you can just do this (if you only have one callback argument):
var stub = sinon.stub(FB,'getLoginStatus').yields([{status:'unknown'}]);

Later you can change the status by calling:
stub.yields([{status:'connected'}]);

See the API doc for details: http://sinonjs.org/docs/#stubs-api

Cheers, Thomas.

Philip Schweiger

unread,
May 20, 2011, 2:41:19 PM5/20/11
to Sinon.JS
That works exactly as I needed, thanks.

Prateek Mehrotra

unread,
Aug 18, 2013, 5:35:55 PM8/18/13
to sin...@googlegroups.com, psch...@gmail.com
Hi Philip,

I need similar help but looks like it is not working Any input is helpful. Below after @ra.post is called I want to return resp.status as "success" but after @ra.do_post call goes directly to lock with console.info("4 ==================")

thnks in advance for help

TEST CASE:

    var qh_obj = new qh("FAKE_ADAPTER");
    sinon.stub(qh_obj.ra,'do_post').callsArgWith(0, {status:'SUCCESS'});

create_test: (id, data, cb) ->
  Async.waterfall [
      (done) ->
         console.info("1 ==================")
        @ra.do_post bll_url, data, done
      , (resp, done) ->
        if resp? and resp.status isnt "SUCCESS"
          cb({error: true, message: "Package switching returned error."})
        else
          console.info("1 ==================")
          fn = () -> self.ra.do_post _url, data , done
          helper.delay 2000, fn

      , (resp, done) ->
        console.info("3 ==================")
        cb(null,resp)
      
    ], (error, resp) ->
      console.info("4 ==================")
      if error
        cb({error: true, message: "#{self.adapter} adapter errored out"})
Reply all
Reply to author
Forward
0 new messages