Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stub.firstCall.returns() #105

Closed
quangv opened this issue Mar 22, 2012 · 14 comments
Closed

stub.firstCall.returns() #105

quangv opened this issue Mar 22, 2012 · 14 comments

Comments

@quangv
Copy link

quangv commented Mar 22, 2012

Hi, I believe my old specs was too verbose and implementation specific. (Before every line I wrote hand an accompany unit test... I'm assuming this is not best practice?)

I'm trying a new way of doing things, is there something like stub.firstCall.returns()

Thanks!

@cjohansen
Copy link
Contributor

Just use stub.returns() and focus on the code that calls it the first time? If that doesn't work I need an example with some context to provide usable advice.

@quangv
Copy link
Author

quangv commented Mar 24, 2012

Kinda like, instead of

callback.withArgs(42).returns(1);

it'll be .onCall(num)

// SUT
animal = function(){
  if(callback() === 1){
    if(callback() === 2){
      return 'cat';
    }
  }
}

// Test
sinon.stub(global, 'callback')

callback.onCall(1).returns(1);
callback.onCall(2).returns(2);

result = animal();
assert.eql(result, 'cat')

Note: callback() would be a more complicated external function... (in my real code it's a database findOne...)

I could use a .withArgs but does Sinon have an onCall or similar functionality? It'll be simpler...

database.findOne({...complicated doc...}, cb)

findOne.withArgs({...gotta recreate complicated doc...}), cb).yields
...

Updated:

To be honest I think my code just needs to be more testable :p but .onCall is an interesting concept nonetheless

@cjohansen
Copy link
Contributor

To be honest I think my code just needs to be more testable :p but .onCall is an interesting concept nonetheless

Hehe, I agree. I'm not so sure about onCall. It's interesting, but I think it will mainly be used to cover up for bad design...

@herb
Copy link

herb commented Apr 17, 2012

i query facebook objects and need to follow each page in the results until nothing's left. the async i/o along with the iterative nature lends itself to a recursive call, i.e.

  getAll = function(fbgraph, query, results, cb) {
    fbgraph.get(query, function (err, res) {
      results.push(res);
      if (res.paging.next) {
        getAll(fbgraph, res.paging.next, results, cb);
      }
      cb(null, results);
    });
  }

invoked like this

getAll(fbgraph, 'me/likes', [], function() { console.log("done",arguments); });

where fbgraph is criso's fbgraph library.

it seems much easier to use a onCall() function vs trying to withArgs everything to get getAll. Especially when arguments are complex objects (in the case of batch calls) withArgs seems to be touchy about matching.

How would you suggest I refactor the code to be more testable? or is this is reasonable use case for something like onCall?

@cjohansen
Copy link
Contributor

I'm not quite sure how you should simplify it. You may be interested in the new matchers that's coming in Sinon 1.4 (already some information about them in the docs). They allow partial matching of object arguments.

@herb
Copy link

herb commented Apr 30, 2012

thanks for the reply.

I did see matchers and ended up installing master at the time which gave me
a reasonable solution to my use case. thanks!
On Apr 30, 2012 6:28 AM, "Christian Johansen" <
reply@reply.github.com>
wrote:

I'm not quite sure how you should simplify it. You may be interested in
the new matchers that's coming in Sinon 1.4 (already some information about
them in the docs). They allow partial matching of object arguments.


Reply to this email directly or view it on GitHub:
#105 (comment)

@Trevoke
Copy link

Trevoke commented May 3, 2012

I have a function that does a rock-paper-scissors battle. It needs to be called a few times. Having this kind of subsequent returns would be very useful (The Ruby mocking framework mocha does this).

@cjohansen
Copy link
Contributor

@Trevoke if you need more sophisticated stubbed behavior than returning a fixed value (or a value paired with some arguments), you could just do

sinon.stub(obj, "meth", function () {
    return Math.random();
});

@Trevoke
Copy link

Trevoke commented May 3, 2012

Well, I can make this work, but it feels hackish (the solutions I will come up with for this particular problem certainly will be). I hesitate to request more behavior from sinon.js, as I do not grok Javascript yet.

@cjohansen
Copy link
Contributor

My stance is that this situation is pushing the limits of how clever you want your stubs and mocks to be. So you can escape the automatic stuff and provide your own function, or you can refactor to make the tests simpler :)

@Trevoke
Copy link

Trevoke commented May 3, 2012

You're probably right.
Thanks for being so responsive :)

On Thu, May 3, 2012 at 1:54 PM, Christian Johansen <
reply@reply.github.com

wrote:

My stance is that this situation is pushing the limits of how clever you
want your stubs and mocks to be. So you can escape the automatic stuff and
provide your own function, or you can refactor to make the tests simpler :)


Reply to this email directly or view it on GitHub:
#105 (comment)

@akhabibullina
Copy link

I also think "onCall().return()" might be very useful. I used them while working with phpUnit. I'd say the goal is the same as for 'withArgs()' - but applied to functions/methods that do not take any parameters.
The example is:

       $inputFile->expects($this->at(0))
                  ->method('read')
                  ->will($this->returnValue("3 4"));
        $inputFile->expects($this->at(1))
                  ->method('read')
                  ->will($this->returnValue("4 6"));
        $inputFile->expects($this->at(2))
                  ->method('read')
                  ->will($this->returnValue(NULL));

where
'$inputFile' is an object under test;
'read' is the method which should return different results on 1st, 2nd and 3rd calls: "3 4", "4 6", NULL accordingly.

Have someone the way to do this with Sinon?

@mantoni
Copy link
Member

mantoni commented Oct 2, 2013

There is an open issue with a long discussion about this feature here: #244
If you are interested, @tf has the current state of development on a branch: https://github.com/tf/Sinon.JS/commits/tf-behavior

@akhabibullina
Copy link

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants