How to mock only one method using Sinon?
Solution 1
Yes, that is one of the most common uses cases for sinon@2, but I believe that what you are looking for is neither a mock nor a spy, but instead a stub.
See: https://sinonjs.org/releases/v2.4.1/stubs/
var stub = sinon.stub(object, "foo");
//do your assertions
stub.restore(); //back to normal now.
This will allow you to create a default function that replaces object.foo()
.
From your question, however, it sounds like a no-op stub function is not what you are after, and instead want to override it with a custom function of your own:
var stub = sinon.stub(object, "foo", function customFoo() { /* ... */ });
//do your assertions
stub.restore(); //back to normal now.
HTH!
EDIT:
How to stub a single function:
The following stubs object.sourceAttackTarget()
var stub = sinon.stub(object, "sourceAttackTarget", function sourceAttackTargetCustom(gameState, source, target) {
//do assertions on gameState, source, and target
// ...
return customReturn;
});
//do any further assertions
stub.restore(); //back to normal now.
How to stub a function to test for particular parameters
var stub = sinon.stub(object, "sourceAttackTarget");
stub.withArgs(1, "foo", "bar").returns("correctTarget");
stub.returns("wrongTarget");
var output = object.sourceAttackTarget(gameState, source, target);
equal(output, "correctTarget", 'sourceAttackTarget invoked with the right arguments');
//do any further assertions
stub.restore(); //back to normal now.
(Update)
There is also .calledWith()
and .calledWithMatch()
, which I just found out about. Could also prove quite useful for these sorts of tests.
How to mock just one method for an object:
"Mocks come with built-in expectations that may fail your test. Thus, they enforce implementation details. The rule of thumb is: if you wouldn’t add an assertion for some specific call, don’t mock it. Use a stub instead. In general you should never have more than one mock (possibly with several expectations) in a single test." - source
... so for the question asked above, a mock is not the right thing to use, and a stub is the appropriate choice. That being said, one of the scenarios can be tested easily with a mock, and that is the expectation that a method has been called with a particular set of arguments.
var mock = sinon.mock(object);
mock.expects("sourceAttackTarget").withArgs(1, "foo", "bar");
object.sourceAttackTarget(gameState, source, target);
mock.verify();
Solution 2
Starting with [email protected], the
var stub = sinon.stub(object, "method", func);
has been removed. One should rather use:
stub(object, "method").callsFake(func)
stub.callsFake(fakeFunction); Makes the stub call the provided fakeFunction when invoked. var myObj = {}; myObj.prop = function propFn() { return 'foo'; }; sinon.stub(myObj, 'prop').callsFake(function fakeFn() { return 'bar'; }); myObj.prop(); // 'bar'
Source: sinonjs docs
Rana Ghosh
Updated on July 22, 2022Comments
-
Rana Ghosh almost 2 years
I've got a single method in my namespace that I'd like to mock, but I'd prefer that all the others work normally. Is it possible to have sinon mock a specific method while leaving the others the same?
My understanding is I'm not looking for a spy because I want to assert that the mock was called with specific parameters.
Here's my code in CoffeeScript:
root.targeting.handleUnitsAttack = (gameState) -> units = gameState.heroes.concat(gameState.badGuys) for source in units for target in units gameState = root.targeting.sourceAttackTarget(gameState, source, target) gameState
I'd like to mock
sourceAttackTarget
and verify that its arguments are specific values. -
Rana Ghosh almost 10 yearsI actually want to verify things at the end. I want to verify that the mock was called with specific parameters.
-
Rana Ghosh almost 10 yearsand in fact, I actually want to control what the mocked method returns too. I feel like I want everything possible, although my code is pretty simple. I'll edit my question to show it.
-
bguiz almost 10 yearsIf you want to verify that the method was called with specific parameters, then a simple stub will suffice. Otherwise, use the second option, where you add the custom function, do your assertions within the custom function for the expected parameters, and then also return a the value that you wish.
-
Rana Ghosh almost 10 yearsCan you update your example showing me how to do that?
-
Rana Ghosh almost 10 years"If you want to verify that the method was called with specific parameters, then a simple stub will suffice." Can you show that part, too?
-
Rana Ghosh almost 10 yearsAnd I'd also appreciate it if you showed how to mock a single function because others will come back here one day with a valid reason to know how to do that and want to see the answer.
-
bguiz almost 10 yearsOK, just edited to add how to stub a function to test that particular parameters were used.
-
bguiz almost 10 years... and just added a section on mocks - with a disclaimer, because mocks are not the right thing to do for what you have asked.
-
Rana Ghosh almost 10 yearsA key to my question is what do I pass in for
object
in this case? Is itroot.targeting
? -
bguiz almost 10 yearsYes,
object
is the variable which contains the function which you wish to stub. In this case, that would beroot.targeting
. What sinon does under the hood isvar methodBeforeStubbing = object[methodName];
-
bguiz almost 10 yearsUpdatred answer to add
.calledWIth()
and.calledWithMatch()
-
k0pernikus over 5 yearsThe answer is out-dated. The correct way to use sinon stub has become
stub(obj, 'meth').callsFake(fn)