how to replace function implementation in a module (e.g. for testing)

68 views
Skip to first unread message

MC

unread,
Mar 8, 2015, 11:39:58 PM3/8/15
to nod...@googlegroups.com
Hello,
I'm trying to override function implementation where original function is part of nodejs module (myMod.js):
'use strict';
function doSomething(req,res) {
 console.log('internal');
}
function doSomethingElse(req,res) {
 doSomething(req,res);
}
module.exports.doSomething=doSomething;

I can override doSomething from the outside:
var myMod = require('myMod.js');
myMod.doSomething = function(req,res) {
 console.log('external');
};

And when I call doSomething new implementation is used (prints 'external').
But when I call doSomethingElse it still prints 'internal' - it looks like inside the module original implementation is used.

I saw a post that suggested declaring a variable (inside module):
var doSomehing = module.exports.doSomething = doSomething;

But using that didn't help.
Any suggestions on how to replace doSomething so that calling doSomethingElse prints 'external'?
Thanks,

M

zladuric

unread,
Mar 10, 2015, 11:14:41 AM3/10/15
to nod...@googlegroups.com
Your module holds internally to the reference of the internal function. Furthermore, it doesn't even know about the external one.

So it means your doSomethingElse needs to address the proper function reference, like override the prototype or use some closure object.

You can try something like this:

`myMod.js`

    function doSomething() {

       console.log('internal');
    }
    function callSomething() {
        obj.doSomething();
    }
    var obj = {

       doSomething: doSomething,
       callSomething: callSomething
    };

    module.exports = obj;


Module usage:

    zlatko@localhost:~/tmp$ node
    > var m = require('./mod')

    > m.doSomething()
    internal

    > m.callSomething()
    internal

    > m.doSomething = function() {console.log('external');}
    [Function]
    > m.callSomething()
    external


The alternative would be that you override the module prototype once you load it.

Zlatko

Ken

unread,
Mar 11, 2015, 2:56:06 PM3/11/15
to nod...@googlegroups.com
You don't actually need a new object (exports already is one), but you do need to make sure within your module you reference exports's attribute that points to the function, rather than referencing the function by name, e.g.

function doSomething() { ... }
exports.doSomething = doSomething;

exports.doSomethingElse = function () {
   // doSomething();  // this will always call the local function
   exports.doSomething();  // calls the exported function, which can be overwritten
}

In practice if doSomething is a function that generally you'd expect to be private to the module and only need to override under special
circumstances I'd recommend either giving it a weird prefix (e.g. _doSomething) or embedding it in a sub-object, e.g.

var private = {
   doSomething: function () { ... }
};
exports.private = private; // export private methods for testing

exports.doSomethingElse = function () { private.doSomething(); }

Then when you're overriding it it will be more obvious that this is an odd thing to do

var myMod = require("myMod);

myMod.private.doSomething = function () { ... }; // override private doSomething method

If you wanted to get fancy you could even make the private export conditional on environment e.g.

if (process.env.NODE_ENV === "development") {
   exports.private = private; // export private methods for testing

Jimb Esser

unread,
Mar 30, 2015, 6:05:45 PM3/30/15
to nod...@googlegroups.com
All of those suggestions involve changing the way you write the code in your module in order to do your tests.  This is problematic because:
a) When you go back and write code later, you may forget to call exports.doSomething and put in a call to just doSomething()
b) You lose useful linting (e.g. if I type exports.doSoemthing() linters won't complain about it, my editor won't immediately highlight it as a typo, etc, as opposed to just doSoemthing(), which linters will complain does not exist).

If I'm mocking out an internal function for testing, I tend to go with the following pattern, which I can add once and then forget about and write Javascript like normal:
function doSomething(req,res) {
 console.log('internal');
}
function doSomethingElse(req,res) {
 doSomething(req,res);
}
exports.doSomething=doSomething;

// Expose overriding a method for testing
function overrideDoSomething(new_func) {
  exports.doSomething = doSomething = new_func;
}
exports.overrideDoSomething = overrideDoSomething;

The same paradigm works for overriding internal-only functions without ever exporting the original internal function.  May also need to also save original functions and expose a resetOverrides() function for cleanup depending on your use case.
Reply all
Reply to author
Forward
0 new messages