> > The problem we've struck is that the private helper functions within each > module can't be accessed from outside the closure for unit testing. We could > of course rely solely on our end-to-end tests to ensure correct behaviour, > but we're striving for more comprehensive coverage than that. Alternatively > we could expose all of these helper methods so that they can be properly > tested, however that defeats one of the primary benefits the pattern, namely > encapsulation. I'm loathe to do sacrifice one benefit for the other, and > ideally want both. >
I tend to think about it this way: if the "private" helpers needs testing on their own, then they probably aren't that private after all. This problem usually goes away when you write tests first. When I TDD my code, I only ever introduce new private "helpers" as an act of refactoring. In this case, all the paths through the private methods currently being used will be tested. Tests should describe the observable behavior of your system, and private methods/state is not part of that behavior. Usually they are implementation details, sometimes they are generally useful utilities unfortunately trapped inside a closure. Retrofitting tests to an existing code base if often much harder than testing new code. One reason for that may be overuse of closures/private "helpers". I feel that private methods are generally used way too much, and often to hide more than implementation specifics. If you have entire concepts that are hard to describe in tests in terms of your public API, you've probably hidden too much. If you cannot easily describe some behavior in a unit test, chances are you cannot easily use it on its own either. This is usually easier to discover when developing API's for other programmers than if you're doing applications. On a general basis my best advice is to consider each private method carefully - is this really private implementation specifics, or could you extract some kind of utility/new public methods from it? Extract meaningful code so it can be tested more easily, and test the rest through the existing public API. > > The only other alternative I can think of is to modify the files at build > time, perhaps exposing the private methods via a temporary test API object > or by removing the outer containing function which constrains their scope. > Of course, that would mean that we'd then be releasing a version of our code > different from the one we'd tested ... which sort of defeats the purpose. > I would advice you not to do that. Keeping the test environment as close to the production environment is key to build trustworthy tests. Tests that can not be fully trusted are worthless and will waste your time. IMHO, exposing methods/state solely for the sake of tests is a code smell, and to me indicates possible failures in API design. You may also be able to solve some problems using mocks/stubs in your tests. > Any thoughts or experiences you have to share would be greatly appreciated. > I'm a relative novice at TDD, so don't hesitate to mention anything you > think seems obvious. Likewise, I'm only a third of the way through Christain > Johansen's excellent book ... so feel free to tell me to at least finish > that before asking such things, if appropriate ;-) > Thanks for the kind words :) > Christian -- To view archived discussions from the original JSMentors Mailman list: http://www.mail-archive.com/[email protected]/ To search via a non-Google archive, visit here: http://www.mail-archive.com/[email protected]/ To unsubscribe from this group, send email to [email protected]
