When I use Sinon on a function inside an object, it works:
function myFunc() {
console.log('hello');
}
var myObj = { myFunc: myFunc };
var spy = sinon.stub(myFunc);
myObj.myFunc();
expect(spy.called).to.be.true();
However, I don't know why when I use Sinon on a standalone function as follow:
function myFunc() {
console.log('hello');
}
var spy = sinon.stub(myFunc);
myFunc();
expect(spy.called).to.be.true();
the assertion fails.
You were kinda on the right path but deviated. Let's walk through your effort and get things right:
// ...
function myFunc() {
console.log( 'hello' );
}
var spiedMyFunc = sinon.spy( myFunc ); // what you want is a 'spy' not a 'stub'
// ...
Then at this point spiedMyFunc
wraps myFunc
. Hence, calling spiedMyFunc()
should mostly amount to the same outcome as calling myFunc()
. Meanwhile spiedMyFunc
additionally
records arguments, this value, exceptions and return values for all calls.
So the rest of the code snippet should go as follows:
// myFunc(); // no you should be calling spiedMyFunc() instead
spiedMyFunc();
expect( spiedMyFunc.called ).to.be.true();
And that is how you spy on a standalone function. However, it does not make conceptual sense to stub a standalone function.
Answer to @charlesdeb's question in a comment on this answer:
When a method is called, it can trigger a chain that implicitly calls other methods. Due to this implicit or indirect calls, you may want to control how other methods in the chain behave while studying the behaviour of a particular method. Stubbing is a means for realising the said control.
When working with functions it is beneficial to actually follow the functional paradigm to make things easy and reliable. Consider this:
function a () { ... }
function b () { a(); }
When testing b
, it is necessary and sufficient to prove that the execution of b()
in turn executed a()
. But with the way b
was implemented, it is impossible to verify that a
was called.
However, if we applied the functional paradigm then we should have
function a () { ... }
function b ( a ) { a(); }
Consequently we can write a simple test as follows:
var a_spy = sinon.spy( a );
var actualOutcomeOfCallingB = b( a_spy );
expect( a_spy.called ).to.be.true;
expect( actualOutcomeOfCallingB ).to.equal( expectedOutcome );
If you'd like to stub a
, then instead of creating a spy with the real a
do so with your preferred stub.
var a_stub = sinon.spy( function () { /* behaves differently than the actual `a` */ } ); // that's your stub right there!
var actualOutcomeOfCallingB = b( a_stub );
expect( a_stub.called ).to.be.true;
expect( actualOutcomeOfCallingB ).to.equal( expectedOutcome );