Recently I was working on some JavaScript that really needed unit tests. I was making a substantial change that could not introduce any regression bugs and is very difficult to black box test. After all, this JavaScript was live! After digging into it a bit, reading the JavaScript spec since I'm more familiar with other languages like C/C++, Java and C#, I came to the conclusion it was going to be difficult so set off on a journey to see how others did it so I could save myself some time reinventing the wheel. My Google search of "unit testing private methods javascript" resulted in coming across the blog post How to Unit Test Private Functions in JavaScript.
The solution provided by Philip Walton was pretty good, but has a couple caveats. First let me explain what his solution is so you don't have to go read his entire post before continuing. He concludes that there are two camps of testing private JavaScript methods:
1. Don't
2. Everything is public
Obviously that isn't so good so he came up with a new option:
3. Export the private methods so they are public but do it in such a way that a code stripper removes them before going live.
The code stripper option isn't much of a stretch because most JavaScript goes through a compression process anyway removing white space and comments. I like his option but for me it wasn't an option to be able to modify the code stripper. We use YUI Compressor and aren't going to modify it. We could add a preprocessor but that isn't an option at this point. Plus there is potential for bugs because the code that is live isn't the same as the code you are testing. Our stripper has been around for a long time so we have confidence in it. So I came up with a new option:
4. If a global variable has been introduced and the .js file is loaded from a specific URL then initialize the global variable with a closure class containing only the private methods you want to test. For example if the URL is contains "http://localhost" or "file://", then initialize the closure. Any URL could be added here, including an internal test URL. However I can see how publishing a private URL is undesirable no matter how difficult it is to read.
For example:
var myclass = function() {
// Private
function someInternalMethod(arguments) {
}
function anotherInternalMethod(arguments) {
}
function initialize() {
if ((typeof __myclassTestHook__ !== 'undefined') &&
(__myclassTestHook__ == null) &&
((window.location.href.indexOf('http://localhost') == 0) ||
(window.location.href.indexOf('file://') == 0))
) {
__myclassTestHook__ = {
someInternalMethod: someInternalMethod,
anotherInternalMethod: someInternalMethod,
};
}
}
// Public
function publicMethod(arguments) {
}
function anotherPublicMethod(arguments) {
}
initialize();
return {
publicMethod: somePublicMethod,
anotherPublicMethod, anotherPublicMethod
};
}();
Now:
Thursday, May 28, 2015
Unit Testing JavaScript
<script>
var __myclassTestHook__ = null;
</script>
<script type="text/javascript" src="testexample.js"></script>
then use it like this:
<script>
var stuff = __myclassTestHook__.someInternalMethod();
</script>
Is this perfect? No, but it comes pretty close in my opinion. What are your thoughts? The biggest concern is introducing security vulnerabilities.
Posted by Chris Bensen at 6:00 PM
No comments:
Post a Comment