Friday, October 20, 2006

Testing Helper Methods

I'm working on some code that ended up having some moderately complex helper methods.  I don't want to expose these methods on the public API because I want to keep my class's public face as simple as possible.  Something I heard Scott Meyers talk about some years back at Software Development Expo has always stuck in my head: “Make your code hard to use incorrectly.” 

That’s always in my head as I’m deciding what bits and pieces of functionality should be exposed.  Helper methods are generally internal bits, not something your class’s consumers should have to worry about, so why should you then expose them on the public side of an API? 

Easy. You shouldn’t.

The issue is how do you create those helper methods when you're doing Test Driven Development?  My first approach was that I just had to figure out all the test cases to drive execution through the various paths of the public function plus its helper function.  That got too complex, but I really didn't want to change that helper to public visibility in order to test it directly.

A few moments with my Thinking Cap on and I came up with this solution: Use the preprocessor and the DEBUG constant.  This lets me have the helper method's signature exposed with a public scope during testing and changed to private when I'm building for release.

 #if (DEBUG)

        public int ProcessGlobalMessages_NoSubscribers(DateTime lastSendTime,

                                                       DateTime thisSendTime,

                                                       bool isEmergency)


        private int ProcessGlobalMessages_NoSubscribers(DateTime lastSendTime,

                                                       DateTime thisSendTime,

                                                       bool isEmergency)


Now I can surround test cases for that method in similar #if blocks and they'll only appear when I'm building Debug releases:



        public void CheckProcessGlobalMessagesNoSubscribersReturnsCorrectCount()


A quick check in Reflector proves things worked as expected in the Release build assembly:

OK, so I’m not 100% happy with this workaround because it’s a fundamental design smell to me in that I can’t get the test coverage I want without a bit of trickery, but this seems like pretty fair compromise between doing my design in a TDD fashion and keeping my class’s public API as simple and clean as possible.


Dan Hounshell said...

Veerrrrry clever, Jim.


MikeWo said...

One way I've been doing this is to use the new InternalsVisibleTo attribute in .Net 2.0. I stumbled across this when I was doing my (very painful) strong naming of Enterprise Library. Basically all you need to do is have the methods you want to expose for testing (but not publicly) be marked internal rather than private. Then, in the assembly file of the project you are testing you can add the assembly: InternalsVisibleTo. You feed it the testing assembly name. You can strong name to add more security around this (but be aware that they want the full public key for the attribute, not the public token which is much easier to type).

Subscribe (RSS)

The Leadership Journey