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.
function myFunc() { console. log( 'hello' ); } var spiedMyFunc = sinon. spy( myFunc ); // what you want is a 'spy' not a 'stub' // ... records arguments, this value, exceptions and return values for all calls.
The function sinon. spy returns a Spy object, which can be called like a function, but also contains properties with information on any calls made to it. In the example above, the firstCall property has information about the first call, such as firstCall. args which is the list of arguments passed.
A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls.
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 );
I am not sure whether there is solution on browser side.
But if you run it in node.js environment, you can export the function and test it in another file.
For example, your source file is source.js
and the test file is test.js
In source.js
function myFunc() { console.log('hello'); } module.exports.myFunc = myFunc;
In test.js
var source = require('./source'); var sinon = require('sinon'); var expect = require('chai').expect; sinon.stub(source, 'myFunc').returns(true); source.myFunc(); expect(sinon).to.be.true;
Hope this can help you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With