Recently, I went over Dependency Injection to help you understand a simple way to decouple your code a little bit and help your testing out. Sometimes, though, in Node.js a module will depend on a system API provided by Node, which can make it pretty difficult to make sure that private dependency is being used properly. Normal dependency injection doesn’t work in this situation, but don’t give up hope just yet.
require
Causes Issues
Node.js made it really easy to import dependencies via require
. It works very nicely and is simpler than AMD module loaders such as RequireJS.The problem comes into play when we want to mock those dependencies. If module loading is controlled via Node.js, how do we take over this responsibility to allow mock objects to be used instead during testing? We can use Node’s vm
module and load the modules into a new context, via vm.runInNewContext
, where we can control the way require
gives back modules.
The Solution
Thanks to this article, a pretty decent and thorough solution can be presented to you right now. If you like this solution, then please give Vojta Jina over at How To Node the thanks and credit. Below is the code:
1 | var vm = require('vm'); |
You can also download the code snippet directly from here. While it might not be the largest chunk of code ever posted into an article, it could still use some explanation. When we are testing, we will load this module into the test, and then use the loadModule
function – instead of require
– to load in the module we will be testing.
The first argument, filePath
, specifies where we’ll find the module that we’ll be testing. The second argument, mocks
, contains an object whose property names will match the names of modules that the module we are testing will try to require
. The value assigned to those properties are the mock objects that you are using to replace the modules that would normally be require
d.
Basically, all it does is use vm
to load and run the module using a different “context”. In other words, we recreate what the globals are (such as require
and exports
) so that we can control them. The thing to notice here is the new require
function that we make available. All it does is check to see if we have a mock dependency for the specified name, and if we don’t, we just delegate to the normal require
function.
Example Using the Module Loader
If you’re still a bit confused, you can take a look at the example code below and seeing it used in context might help you figure things out a bit. First, we’ll just create a simple module.
1 | var fs = require('fs'); |
Just imagine it is something cool, ok? Anyway, now we want to test that module, but we want to mock fs
to see how it’s being used internally.
1 | // Jasmine's syntax http://pivotal.github.com/jasmine/ |
The main thing to pay attention to here is lines 7 through 12, where we create a mock object for fs
and use our new loadModule
function to tie the mock object in as the object being used in our above worthless little module (I mean awesome! Remember, it’s awesome, right?).
Conclusion
In my mind, this just fortifies the greatness of Node.js. It allows you to change the context in which it runs! This is a really interesting way to emulate dependency injection, and I’m sure it can be useful for far more. Anyway, keep testing, keep using good practices, and as always, God bless and happy coding.