Easy mocking in Node.js

I’m a big believer in unit testing. Not only because it allows me easy code refactoring and faster regression testing, but because I can deliver product much faster doing unit tests. Yes, writing more code (unit tests) shortens product delivery time. But this is another topic.
 
Efficient unit testing is not possible without mocking. In Node.js I was a happy user of rewire. I liked it. Until today. For whatever reason it stopped working for me. Either it doesn’t like me anymore or something wrong with me, but it refuses rewire modules.
 
So, I’ve spent some time looking for another mocking framework. There is a number of good ones around. But all of them didn’t feel 100% right. Especially when I compare them with framework available for C# or Java that I’m used to.
 
So, can mocking be easily and nicely done without framework? Sure, the same way I have never used any IoT/DI frameworks with C# – always used simple manual injection.
 
And it’s actually very easy with Node.js.
 
In the following code, I need to test create function. There are 2 calls that need to be mocked for unit tests: inboxDb.create and inboxProcessor.processEvent. Here is a manual mocking with  just a few lines of code – check the mock setters (t the bottom of the code.
 
'use strict';
var moduleName = 'inbox.controller'

var Promise = require('bluebird'),
appRoot = require('app-root-path')

var inboxDb = require(appRoot + '/server/components/inboxProcessor/inbox.db'),
MessageModel = require(appRoot + '/server/api/messaeg/message.model'),
inboxProcessor = require(appRoot + '/server/components/inboxProcessor/inboxProcessor')

/**
* Processes incoming message.
* @param req
* @param res
*/
exports.create = function (req, res) {
var payload = req.body.m
var ipAddress = req.connection.remoteAddress;
console.log('%s|create|payload:%s', moduleName, payload)

var message = {}
inboxDb.create(payload, ipAddress).
then(function(result) {
try {
message = MessageModel.parsePayload(payload, ipAddress)
return Promise.resolve(message)
} catch(error) {
console.log('%s|create|parsePayload|Error: ', moduleName, error)
return res.send(204, 'poison')
}
}).then(function(event) {
return inboxProcessor.processEvent(event, payload, undefined)
}).then(function(result) {
return res.json(201, result)
}).
catch(function(error) {
console.log('%s|create|Error: ', moduleName, error)
return res.send(500, error)
})
}

/* Mock setters */
exports.setInboxDb = function(mock) {
inboxDb = mock
}
exports.setInboxProcessor = function(mock) {
inboxProcessor = mock
}
 
Now, with this setters in place, mocking is actually very easy in the unit test:
'use strict';

var Promise = require('bluebird'),
should = require('should'),
request = require('supertest'),
appRoot = require('app-root-path')

var app = require(appRoot + '/server/app'),
target = require('./inbox.controller')

describe('POST /api/inbox', function () {

it('should process message', function (done) {
target.setInboxDb(setDbMock('ok', false))
target.setInboxProcessor(setInboxProcessorMock('ok', false))

var data = { "m": "message - actual content is not important"}
request(app)
.post('/api/inbox')
.send(data)
.expect(201)
.expect('Content-Type', /json/)
.end(function (err, res) {
if (err) return done(err)
res.body.should.equal('ok')
done()
})
})

})

function setDbMock(result, throwError) {
var mock = {
create: function(payload, ipAddress) {
if (throwError) {
var error = {message: 'db error'}
return Promise.reject(error)
}

return Promise.resolve(result)
}
}
return mock
}

function setInboxProcessorMock(result, throwError) {
var mock = {
processEvent: function(event, payload, next) {
if (throwError) {
var error = {message: 'error'}
return Promise.reject(error)
}

return Promise.resolve(result)
}
}
return mock}
 
By replacing actual invocation with our mocked functions, the code is easier to test and debug (in this case I’ve just created a wrapper that allows me to return some result or throw an error):
target.setInboxDb(setDbMock('ok', false))
target.setInboxProcessor(setInboxProcessorMock('ok', false))
 
Yes, it’s minimalistic and doesn’t have all the bells and whistles of other frameworks. But, it’s simple and will cover 80% of the mocking needs.
 
Update. I’ve opened another set of unit tests with rewire today and it worked flawlessly. I’m not sure why the first set didn’t work, but I’m glad that I’ve found this simple solution and will stick with it for now.