Reputation: 157
I'm creating a small project in nodejs that is a wrapper for an API. I'm writing some unit tests using nodeunit and need to inject various mock functions into the module (for example a function that simulates making a HTTP request to the server and outputs various different responses to test my code against).
The question I have is how do I inject these functions into my module?
I've identified two methods that should theoretically work as follows:
Rename the folders of the modules I would like to replace and add a new folder containing the code I'd like to inject e.g:
./node_modules/request -> ./node_modules/request.tmp
./tests/myRandomFunction -> ./node_modules/request
After performing the tests I would then do the opposite:
./node_modules/request -> ./tests/myRandomFunction
./node_modules/request.tmp -> ./node_modules/request
This seems rather hacky and is not something I'd like to attempt even though it should theoretically work.
This is my preferred method utilising my modules initialisation. My module takes a JSON object that can contain various options as follows:
var module = require('./module')({
option1: '',
option2: '',
...
});
I am planning on adding a key to this JSON object called '_testing' with the value of a JSON object containing various functions for example:
var module = require('./module')({
_testing: {
request: function() {return false;}
}
});
In my module I could then do the following:
eval(''+key+' = this._testing.'+key) //eval('request = this._testing.request')
/*
eval can be dangerous I should probably perform some validation for example is key a function we want to be replaced? Can I check if nodeunit is testing my module and if it isn't don't do anything?
*/
Is there a better way to inject / replace a function in my module for testing purposes?
Upvotes: 3
Views: 9724
Reputation: 4671
This is called "mocking" or "stubbing". It's a common necessity while testing, and there's a variety of libraries. Possibly the most popular is Sinon.
With Sinon you can do something like var stub = sinon.stub(request, [methodName]).returns(false)
(or any other return value). You can also do things like stub.expects(42)
to assert that the function receives that as a parameter when invoked.
Upvotes: 1