views:

200

answers:

4

Is it possible to test myInnerFunction below?

var val = function() {
    var myInnerfunction = function(input) {
        return input + ' I ADDED THIS';
    };
    return myInnerfunction('test value');
}();

Because myInnerFunction is essentially a private member of the anonymously executed outer function, it doesn't seem like it is testable from the outside.

+1  A: 

afaik unit testing does not concern about internal workings of things you test. The point is that you test the functionality ie: it does what it's supposed to do, not how it does it. So if it uses an internal private member, it should not be testable...

Nicky De Maeyer
+1  A: 

You can test the external behavior that is observable. In this simple case you returned just the value of the inner function, but in a real world example you might combine the result of that inner function with something else. That combination is what you would test, not the direct outputs of the private method.

Trying to test the private method will make your code difficult to change and refactor, even when the external behavior is preserved. That said, I like to view unit tests not as extensive tests of your code, but simply providing an example of the API and how it behaves to different conditions. ;)

James Carr
+4  A: 

You could intentionally expose a testing hook to the outside world, like possibly this:

var val = function() {
   var myInnerfunction = function(input) {
      return input + ' I ADDED THIS';
   };
   /* START test hook */
   arguments.callee.__test_inner = myInnerFunction;
   /* END test hook */
   return myInnerfunction('test value');
}();

now, once val has been run at least once, you can reference val.__test_inner and call it with testable inputs.

The benefits to this approach: 1. you choose what is exposed and not (also a negative 'cause you have to REMEMBER to do so) 2. all you get is a copy-reference to the private method, so you can't accidentally change it, only use it and see what it produces

The drawbacks: 1. if the private member changes (or relies on) state of its host/parent function, it's harder for you to unit test around that, since you have to recreate or artificially control the host/parent state at the same time 2. As mentioned, these hooks have to be manually added

If you got really clever, you could have your build process look for blocks of comments like the above and remove the test hooks when creating your production build.

Kyle Simpson
I like your approach, although I do want to try to keep the production code as clean as possible. What I'm really doing is providing a function to a library's Dom-ready event handler, so I don't know if I could do this and still get access to it from the library.
Matthew Taylor
that's exactly why i suggested the build-process strip out blocks of formatted comments like the above.
Kyle Simpson
+1  A: 

I think my answer for this is (like so many things) that I'm doing it wrong. What I've defined as a 'private' function is really something that needs to be tested. It was only private because I didn't want to expose it within a utilities api or something like that. But it could still be exposed through my application namespace.

So within the anonymous function that is executed on-dom-ready, I just attach my pre-defined functions as event handlers to the proper DOM hooks. The functions themselves, while not stored with my more open utilities functions, are still stored publicly within a package in my namespace associated with the DOM structure they are dealing with. This way I can get at them and test them appropriately.

Matthew Taylor