Thursday, April 09, 2009

Functional thinking, unit testing, and the hole in the middle

Generalizing the "hole in the middle" pattern can be a good way to make a method that at first blush appears to be unsuited to unit testing into a fully testable one.

Consider the code

which is intended to find the app.config file for a service, and extract the WCF endpoint listening port from it. Now, even given a fully mocked ServiceInstallPath() -- assume that involves a protected abstract method somewhere in its body so we can PartialMock that -- there is a problem with that direct access to the filing system in the middle.

Well, this is something where we essentially turn the "hole-in-the-middle" around. Adjust the sequence to create the XmlDocument before looking at the file, and do an Extract Method to get

And now we replace the explicit GetFileStream with a Func<string, Stream> or an equivalent delegate type passed in as an argument

to give us a couple of new one-liner methods which can safely be tested by inspection, and the previously untestable core functionality in the newly refactored and, most importantly, functional method is now fully testable.

Yes, the code here is raw but now we have separated out all the real work, so that can be tested to destruction (and extended to handle all the XmlException and IOException cases which the original method just falls over with). The unit test fixture can provide its own Func<string, Stream> implementations that can both assert that the path is correctly constructed and can provide an arbitrary mocked stream to drive the XML parsing through various states, without having to worry about what is happening -- or not -- to the filing system.

Post a Comment