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

Possibility to call an arbitrary function from stubs #118

Closed
fhd opened this issue Apr 15, 2012 · 23 comments
Closed

Possibility to call an arbitrary function from stubs #118

fhd opened this issue Apr 15, 2012 · 23 comments

Comments

@fhd
Copy link

fhd commented Apr 15, 2012

I'd like a function calls(f) on stubs that allows me to execute arbitrary code when the stub is invoked. That function f could get all the arguments the initial function was called with.

I'll gladly provide a pull request for this, but I'd first like to make sure it has a chance of getting accepted.

@cjohansen
Copy link
Contributor

This already exists:

sinon.stub(obj, "meth", function () {
    // Whatever you want in here
});

@fhd
Copy link
Author

fhd commented Apr 17, 2012

Brilliant! And it´s right there in the documentation, too! Sorry, missed it somehow.

@reinseth
Copy link

reinseth commented Dec 9, 2013

I vote to reopen this because of the following:

// Argument matching
var stub = sinon.stub();
stub.withArgs("a").calls(f);
stub.withArgs("b").returns(something);

@cjohansen
Copy link
Contributor

There already is a way to execute custom logic. I generally think non-trivial logic in tests is a bad idea, and don't want to encourage it with further features in this direction.

@reinseth
Copy link

I wouldn't say that mocking a contract in a test is a bad idea, nor that it should be non trivial. An example could be a request handler in a router:

var mockRequest = sinon.stub();
mockRequest.withArgs(someReq, someRes).calls(function(req, res) {
  res.send('mock result 1');
});
mockRequest.withArgs(someOtherReq, someOtherRes).calls(function(req, res) {
  res.send('mock result 2');
});

This could of course be achieved with "yieldsTo", but I think that is non obvious and doesn't read very well.

However, I understand that you don't want to add to an already large api.

@floatdrop
Copy link

I also stuck with this:

var mockRequest = sinon.stub();
mockRequest.onThirdCall().calls(function() {
    console.log('Yes!');
    done();
});

Any hints on how this can be achieved is requested. :(

@vitalybe
Copy link

That would be very useful. For now, I have to make my own stub function for that :(

@shakiba
Copy link
Contributor

shakiba commented Feb 6, 2015

Why there should be an object and "method" to be able to stub(fn)? I can't understand what is the difference with spy(fn)?

@peterflynn
Copy link

+1 to @shakiba's comment. The 'answer' here, sinon.stub(obj, "meth", function () { ... }), only works when stubbing a method on an object. When creating a freestanding method stub with sinon.stub() (e.g. to pass something else as an event listener or callback), you can't use this solution.

The workaround is ugly:

var fakeObject = { fn: function () { } };
sinon.stub(fakeObject, "fn", function () { ... });
var stubIWanted = fakeObject.fn;

I'd much rather have a clean syntax like:

var stubIWanted = sinon.stub(function () { ... });

@mantoni
Copy link
Member

mantoni commented Aug 12, 2015

@peterflynn You can do this with a spy:

var spyYouWant = sinon.spy(function () { ... });

@Twipped
Copy link

Twipped commented Nov 4, 2015

@mantoni a spy doesn't let you define different behavior for different invocations.

I also have a use case for stub.onSecondCall().calls(function() {}). I want to perform my own assertions during those calls.

@joniba
Copy link

joniba commented Nov 13, 2015

+1 for @ChiperSoft's use case

@bion
Copy link

bion commented May 17, 2016

+1 for @ChiperSoft's proposed change

@fatso83
Copy link
Contributor

fatso83 commented May 18, 2016

@ChiperSoft You are perfectly capable of defining different behaviour for different invocations yourself. Just check the callcount in the spy.

@bion We are trying shrink the API down for 2.0. See if you can create a wrapper/plugin to extend the core functionality if you think this is useful and publish it to NPM if it works for you.

@Twipped
Copy link

Twipped commented May 18, 2016

What I ended up doing was producing my own function stubbing library that let me define callbacks for each invocation. It makes the tests a lot simpler and it let me remove sinon from my projects entirely. http://npm.im/stepperbox

@ppyoosuf
Copy link

my stub is executing the original method why

@fatso83
Copy link
Contributor

fatso83 commented Jun 23, 2016

@ppyoosuf please post usage questions to the mailing list or stack overflow, after reviewing the docs. If you find an actual issue/bug, try opening a new issue and post enough code for us to verify the issue.

@ppyoosuf
Copy link

his is my controller function in node.js

exports.searchDocument=function(req,res){ var type=req.query.docType; var
dep=req.query.dep; var serStr=req.query.serStr; var result; //
console.log(req.session.userMode); res.writeHead(200, {"Content-Type":
"application/json"});

    if(type===''||type===null || isNaN(type) ||dep===''||dep===null)

    // console.log("type:"+type+"dep="+dep);

    if(type==='-1' && dep==='-1')
    {
      docService.getAllDoc(serStr,function(err,data){
          if(err) throw err;
          result=data;
          res.end(JSON.stringify(result));
      });
    }
    else if(type==='-1')
        docService.getDocByDep(serStr,dep,function(err,data){
            if(err) throw err;
            result=data;
            res.end(JSON.stringify(result));
      });
    else if(dep==='-1')
      docService.getDocByType(serStr,type,function(err,data){
          if(err) throw err;
          result=data;
          res.end(JSON.stringify(result));
      });
    else
      **docService.getDocByTypeDep**(serStr,type,dep,function(err,data){
          console.log(data);
          console.log(err);
          if(err) throw err;
          result=data;
          res.end(JSON.stringify(result));
      });
                 };

here docService.getDocByTypeDep is a database service function

this.getDocByTypeDep=function(ser,typeId,depId,cb){

var myErr=null,data=null;
if(typeId==null || typeId=='' || depId==null || depId=='' ) return
cb("error",data);
var qry="";

con.query(qry,typeId,function(err,res){

if(err)
{
myErr=err;
cb(myErr,data);
}
else
{
data=res;
cb(myErr,data);
}
});

     };

i wrote the test cases by sinon stub ,but it executing the original function

it('returns the result', function(done) {
   var stub = sinon.stub(docService, 'getDocByTypeDep');
    var req = {
        query:{
            docType: '2',
            dep:'4',
            serStr:"a"
        }
    };
    // we provide the response object which the controller uses
    var res = {
        end: function(data) {
            expect(data).to.be.a("string");
            stub.restore();
            done();
        },
        writeHead:function(){

        }
    };
    // var error = new Error('Authentication failed.');
    stub.callsArgWithAsync(3,error,error);
    controllerToTest.searchDocument(req,res); // call the function

to be tested

           });

    please help me

On Thu, Jun 23, 2016 at 12:16 PM, Carl-Erik Kopseng <
notifications@github.com> wrote:

@ppyoosuf https://github.com/ppyoosuf please post usage questions to
the mailing list or stack overflow, after reviewing the docs. If you find
an actual issue/bug, try opening a new issue and post enough code for us to
verify the issue.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#118 (comment), or mute
the thread
https://github.com/notifications/unsubscribe/APpoQazXq7BUm113wp7--RlxDaukOcMYks5qOivEgaJpZM4BSxXv
.

@mantoni
Copy link
Member

mantoni commented Jun 23, 2016

@ppyoosuf We are trying to keep the GitHub issues list tidy and focused on bugs and feature discussions. This is a usage question, please post it to the Sinon.JS mailinglist, so the bigger community can help answer your questions.

@ppyoosuf
Copy link

OK

@supoved
Copy link

supoved commented Nov 18, 2016

Without this feature use of fake timers is a pain.
I have a method witch is called inside black box multiple amount of times with a timeout, to test black box I need to be able to control clock.
So I want to call clock.tick every time specific stub is hit, also I have defined behavior for this stub through withArgs and yields.

I would like to see something like:

var clock = sinong.useFakeTimers();
var stubbedMethod = sinon.stub();
stubbedMethod.onHit(()=>clock.tick(1000)).withArgs('page1').yields(null, [12, 45, 69]);

It's achievable only through by specific construction of stub, which is not always convenient or possible:

sinon.stub(object, 'method', function(callback){
  clock.tick(1000);
  callback();
})

Ability to change state of a test/environment on call is important for a lot of different tests and crucial to have in mock library.

@DaGaMs
Copy link

DaGaMs commented Mar 26, 2017

in sinon 2.1, callsFake() will do exactly this

@cjrd
Copy link

cjrd commented Jan 31, 2018

I didn't see this solution posted above, so adding incase it helps others:

Using the spy interface to get the args of the nth call

var someFunctionSpy = sinon.spy(someFunction)
someFunction()
var nthCallArgs = someFunctionSpy.getCall(n)

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