Spies and stubs with Sinon.js

Testing your code will prove to be extremely difficult if there isn't an easy way to spy on functions and know whenever they are called. Additionally, when one of your functions is called, it will be nice to know what arguments were passed to it and what was returned. In testing a spy is a special placeholder function that replaces an existing function when you want to check specifically if/when it was called. Spies track a number of properties for a function when it's called, and they can also pass through the expected functionality of the original function. The Sinon.js library provides both spy and stub functionalities and is quite extensive. For a complete list of the different options available with this powerful framework, I strongly recommend that you spend some time reading the documentation at http://sinonjs.org/docs.

Since we will use Sinon.js with our tests, we should install it as another devDependency, exactly the same way we did with Chai.js. In addition, we should also install the sinon-chai helper, which provides additional chai assertion verbs, specifically for use with Sinon:

    $ npm install --save-dev sinon sinon-chai

The inclusion of sinon-chai allows us to write special assertions, such as to.be.calledWith, which would otherwise not work with chai alone.

Imagine that you have a function that simply adds two numbers together and returns the sum:

let sum = (a, b) => {
return a + b;
}
let doWork = () => {
console.log("asdasd")
const x = 1,
y = 2;
console.log(sum(x, y));
}

When writing a test for the doWork function, we want to assert that the sum function was called. We don't necessarily care what the function does or whether it even works; we just want to make sure--since doWork relies on sum--that it's actually calling the function() function. In this scenario, the only way we could be sure is if we had a way to spy on the sum function and know whether it was ever called. Using spy, we can do just that:

const chai = require('chai');
const expect = chai.expect;
const sinon = require("sinon");
const sinonChai = require("sinon-chai");
chai.use(sinonChai);

describe('doWork', ()=>{
let sum;

it('should call sum', ()=>{
sum = sinon.spy();
doWork();
expect(sum).to.be.calledWith(1,2);
});
});

In the preceding scenario, the sum function is replaced with a spy function. So its actual functionalities will no longer exist. If we want to ensure that the sum function is not only spied on but still functions the way we expect, we will need to attach .andCallThrough() after sinon.spy():

describe('doWork', ()=>{ 
let sum;
console.log = sinon.spy();

it('should call sum', ()=>{
sum = sinon.spy().andCallThrough();
doWork();
expect(sum).to.be.calledWith(1,2);
expect(console.log).to.be.calledWith(3);
});
});

Note that by including andCallThrough on our sum spy, we're able to not only spy on it and assert that it was called, but also spy on the console.log function and assert that it was called with the correct value returned by sum.

Where a spy is typically just a watcher of a function and only reports whether the function was called, a stub allows you to provide custom functionalities for a function on the fly during test execution. Test stubs are said to be preprogrammed behavioral functions that are used to test wrapped boilerplate code required as a module dependency in an application.

Think of stub as a super spy, where it reports the same things that a spy does, but also performs whatever specific tasks you want as well. Using the same example, let's stub the sum function to always return the same value:

it('should console.log sum response', ()=>{ 
// replace the existing sum function with a new stub,
// a generic function that does exactly what we specify
// in this case always just return the number 2
sum = sinon.stub(()=>{
return 2;
});


// lets replace the standard console.log function
// with a spy
console.log = sinon.spy();
// call our doWork function (which itself uses console.log)
doWork();
// and if doWork executed the way its supposed to, console.log
// should have been called and the parameter 2 passed to it
expect(console.log).to.be.calledWith(2);
});

Stubbing a function is great when a function performs work that might yield unexpected results, and you just want to force the response for the purposes of your test. Stubbing is also handy when you're doing TDD and you're testing against a function that you haven't even written yet.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.221.144