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.
1 comment :
Very interesting post ...
Post a Comment