Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sinon spy on standalone function

Tags:

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.

like image 384
giangnn Avatar asked Aug 31 '15 22:08

giangnn


People also ask

How do you spy a method using Sinon?

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.

What does Sinon spy do?

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.

Which of the following Sinon test function that records arguments Return value the value of this and exception thrown if any for all its calls?

A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls.


2 Answers

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 ); 
like image 145
Igwe Kalu Avatar answered Sep 18 '22 23:09

Igwe Kalu


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.

like image 39
Yu Huang Avatar answered Sep 21 '22 23:09

Yu Huang