How to Mock redis
datastore
Mocking and stubbing walk hand in hand. stubbing redis
pub/sub, a datastore widely adopted in nodejs
ecosystem, can be a setback when testing WebSocket endpoints. This article brings clarity, and a path forward, to it.
In this article we will talk about:
- Stubbing
redis
clients - Replacing a
redis
with a drop in replacement. - How to avoid spin-up a
redis
server.
Even though this blog post was designed to offer complementary materials to those who bought my Testing
nodejs
Applications book, the content can help any software developer to tuneup working environment. You use this link to buy the book.
Show me the code
module.exports = function(req, res, next){
User.findById(req.user, (error, next) => {
if(error) return next(error);
new Messenger(options).send().then((response) => {
redisClient.publish(Messenger.SYSTEM_EVENT, payload));
//schedule a delayed job
return res.status(200).json({message: 'Some Message'});
});
});
};
//service based equivalent using a service layer
module.exports = function(req, res, next){
UserService.findById(req.user)
.then(new Messenger(options).send())
.then(new RedisService(redisClient).publish(Messenger.SYSTEM_EVENT, payload))
.then(response => res.status(200).json(message);})
.catch(error => next(error));
};
The use of arrow functions instead of function keyword serves to shorten the code. It is possible to replace all arrow functions with the
function
keywords, for readability.
What can possibly go wrong?
The following points may be a challenge to mock datastore access:
- Same level of challenge as when mocking database access functions
- Asynchronous nature of pub/sub clients, characteristic to queue processing systems
- When the application is using
redis
(local or remote) - Running tests without spinning up a
redis
server
The following sections will explore more on making points stated above work.
Show me the tests
There is more than one way to go with mocking. I have to preview 3 libraries and choose one the fits better my needs.
Some of libraries are we can tap into to make mocking possible are : rewire
, fakeredis
, proxywire
and sinon
.
Mocking redis
using rewire
var Rewire = require('rewire');
//module to mock redisClient from
var controller = Rewire("/path/to/controller.js");
//the mock object + stubs
var redisMock = {
//get|pub|sub are stubs that can return promise|or do other things
get: sinon.spy(function(options){return "someValue";});
pub: sinon.spy(function(options){return "someValue";});
sub: sinon.spy(function(options){return "someValue";});
};
//replacing --- `redis` client methods :::: this does not prevent spinup a new `redis` server
controller.__set__('redisClient', redisMock);
Example:
Mocking redis
using fakeredis
. fakeredis
provides an thrown in replacement and functionalities for redis
's createClient()
function.
var redis = require("redis");
var fakeredis = require('fakeredis');
var sinon = require('sinon');
var assert = require('chai').assert;
var users, client;
describe('redis', function(){
before(function(){
sinon.stub(redis, 'createClient', , fakeredis.createClient);
client = redis.createClient(); //or anywhere in code it can be initialized
});
after(function(done){
client.flushdb(function(error){
redis.createClient.restore();
done();
});
});
});
Example:
Two of the alternatives whose examples are not figuring in this article are mocking redis
usingredis-mock
and proxyquire
.
The goal of the
redis-mock
project is to create a feature-complete mock of [`redisnode](https://github.com/mranney/node_redis), so that it may be used interchangeably when writing unit tests for code that depends on
redis`_
Conclusion
In this article, we revisited strategies to mock redis
access methods and replace response objects with mock data.
Testing in parallel can stress the redis
server. Mocking redis
clients makes tests faster, reduces friction on the network, and prevent stressing redis
server especially when shared with other production applications.
There are additional complimentary materials in the “Testing nodejs
applications” book.
References
- Testing
nodejs
Applications book - Faking
redis
innodejs
withfakeredis
~fakeredis
package homepage ~ a tutorial. redis
mock ~ first library I looked into.- Mock
redis
Client, then stub function withsinon
~ rewire ~ StackOverflow Answer rewire
~ Easy monkey-patching fornodejs
unit tests ~ Github Rewire Libraryproxyquire
~ Proxiesnodejs
require in order to allow overriding dependencies during testing Github Library