This seems impossible (and it might be), but I'm trying to get into more TDD and I keep hitting a wall with closures. Say I have the following:
function createSomething(init) {
function privateMethod(param) {
return init[param]; //assuming this is more complicated, how can you test it?
}
function getData() {
return init.data;
}
function getValue(name) {
if (name === "privateNode" || typeof name !== "string") {
return "permissionDenied";
}
return privateMethod(name);
}
return {
getData : getData,
getValue: getValue
};
}
Putting aside this code probably isn't the best illustration of my point and assuming "privateMethod" is something much more complicated than what is above, is there any way to run unit tests on methods like "privateMethod" or is the best you can do is to test the object created by createSomething? I ask because large parts of my application are hidden inside closures. I'm pretty uninformed in this area, but it seems to me that this is a weak spot for javascript and tdd.
fiddle for the code above without tdd is here: http://jsfiddle.net/QXEKd/
You can "smuggle" a function (or an Object of functions, variables, etc) out of your closure quite easily by adding an extra parameter to the constructor or hard-coding an early return. The smuggled function should still have the closure from where it was smuggled from unless you're doing something like the evil eval
.
It might me worth noting that if you're taking functions out like this for testing purposes only, it may be preferable to comment out or otherwise remove the code to access these before publishing it on your website, so it can't be abused. Also, be aware that this
will change depending on how a function is invoked, if you are using it.
For example
function createSomething(init, aaa) {
function privateMethod(param) {
return init[param]; //assuming this is more complicated, how can you test it?
}
function getData() {
return init.data;
}
function getValue(name) {
if (name === "privateNode" || typeof name !== "string") {
return "permissionDenied";
}
return privateMethod(name);
}
// ----------------------------------
if(aaa) return privateMethod;
// ----------------------------------
return {
getData : getData,
getValue: getValue
};
}
var something = createSomething({
privateNode : "allmysecrets",
id : "1234",
data : {
stuff : "32t97gfhw3hg4"
}
}, 1); // passing extra arg to get method
console.log(
something('id'),
something('privateNode')
) // 1234 allmysecrets
Another possibility is to export a function that adds test-cases. It wouldn't export anything that's meant to be out-of-reach (private).
I mostly use Mocha for testing, so I call "describe()" and "it()" from that function that adds tests. For example, let's say I have created a library called "whatever." I could create a function "test" (or _test, _addTests, ...):
var whatever = (function() {
var insideClosure = "Ha ha!";
return {
// obviously you would have other functions too
test: function() {
describe('something', function() {
it('should work', function() {
assert.equal(insideClosure, "Ha ha!");
});
});
}
};
})();
Then my ./test/tests.js would have:
whatever.test();
One obvious bad point with this is the fact that you can't separate pure code and tests (unless maybe by using some kind of deployment workflow).