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.
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.
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:
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
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
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
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.
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.
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?).
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.