Stubbing node modules with Proxyquire

Spies and stubs are great when writing tests against code within the same module, but when you need to spy on or stub a module required within another Node module, things get a little trickier. Fortunately, there's a tool called Proxyquire that will allow you to stub modules that are required from your code.

Examine the following code sample:

// google.js 
const request = require('request'),
sinon = require("sinon"),
log = sinon.spy();


module.exports =()=>{
request('http://www.google.com', (err, res, body)=>{
log(body);
});
}

You can see that we require the request module. The request module accepts two parameters, one of which is a callback function. This is where things start to get tricky. How are we going to implement spies and/or stubs in this type of scenario? Furthermore, how can we prevent our tests from explicitly making a network call to fetch google.com? What if google.com is down (ha!) when we run our tests?

In order to be able to spy on the request module, we will need a way to intercept actual require and attach our own stubbed version of request instead. The request module is actually a great example of a module that you would want to stub, because request is used to make a network call, and that's something that you want to ensure that your tests never actually do. You don't want your tests relying on an external resource, such as a network connection or being dependent on the data returned from a live request.

Using Proxyquire, we can actually set up our tests in a way that they'll intercept the require module and replace what gets executed with our own stub. Here's an example of a test file written against the module we created earlier:

//google.spy.js
const sinon = require("sinon"),
proxyquire = require('proxyquire'),
log = sinon.spy(),
requestStub = sinon.stub().callsArgWith(1, null, null, 'google.com'),
google = proxyquire('./google', { 'request': requestStub });

describe('google module', ()=>{
beforeEach(()=>{
google();
});
it('should request google.com', ()=>{
expect(reqstub).to.be.called();
});
it('should log google body', ()=>{
expect(callback).to.be.calledWith(null, null, 'google.com');
});
});

The first thing the test suite does is set up a spy and a generic stub function that will be used as the request module. Then, we include our google module, but we do it using proxyquire instead of a typical require module. Using proxyquire, we pass the path to the module the same way we would with require, except the second parameter is the module that would be required within that module and the stub function to use in its place.

Before each test, we will execute the original google module and assert against our stub that it was, in fact, called. Additionally, we assert that the log spy was called with whatever data was returned from the request module. Since we are in control of that module, we can test, quite literally, that the string google.com was returned when a request was made to http://google.com (which we know for a fact is not true--not only that, but we know that a network call was never sent to www.google.com, either).

We're using a special power of a stub that allows us to execute a particular parameter to the stubbed function, assuming that it was a callback function. Here, we're using callsArgWith and including the argument index (zero based) as the first parameter; in this case, one of the two parameters that were passed to the request, the first (index 0), was the URL itself, and the second (index 1) was the callback function. Using callsArgWith, we can execute the callback function and specifically provide its parameters, in this case, null, null, and a string. Like Sinon.js and Chai.js, proxyquire will also need to be included in our project as devDependency:

    $ npm install --save-dev proxyquire
..................Content has been hidden....................

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