Monday, May 05, 2008

Exploratory Surgery and Unit Testing

Test Driven Development is one of those milestones in your development career that once reached, seldom causes you to look back. When writing unit tests before you write the code to pass them becomes second nature, and re-running the unit tests on each change becomes part of the development process, quality simply mushrooms.

But the Church of TDD has several orthodoxies. One sect insists that only the public parts of a unit should be tested. Another says that everything needs to be tested, public or private. I'm a proud member of a third group, whose credo is expounded by Cedric Beust: When it comes down to testing, I follow a simple rule: "if it can break, test it." This pragmatic position seems perfect for the agile developer. Still, as much as possible, I try to keep my private methods lightweight and stick to testing the visible public methods, exercising them extensively enough to make sure the underlying private ones work.

However, I was recently putting together some code that served as a dispatcher: a public method would dispatch to one of a number of private methods depending on some set of conditions. Normally I'd just set up each condition and make sure the returned value was what was expected. But in this case, the dispatching was done inside a new Thread, and no reasonable surface value was returned to check. I needed to get under its skin and test the private methods.

Ruby is kind to testers. I'm a big fan of extending a class within the unit test code itself that will let me do a more complete job. Exposing an attribute or mocking a return value in the testing code is all part of the game, as long as I'm not changing the code I'm releasing. If I have to slip something into the code under test, then it's too dirty. It shouldn't have any inkling being tested, otherwise the system breaks down, governments collapse and fire starts raining from the sky. No thank you.

Instead, one needs to do exporatory operations with surgical instruments. Probe the body, touch a nerve, see what twitches. And for god's sake, don't change anything! In this sense, the private method is the nerve you're touching - what is needed is the probe that lets you get at it.

As everyone knows, testing a public method, say bar, is easy:
   def test_bar
Foo foo = Foo.new
assert_equal foo.bar, expected_bar,
"all is not well in Foo's bar."
end
but if we have a private method, frapp, you need to get at it surgically. I opt for a variation in a mechanism proposed by Jay Fields that offers less exposure:
class Class
def publicize_private_instance_method(method)
needs_publicity =
self.private_instance_methods.include? method.to_s
public method if needs_publicity
yield
private method if needs_publicity
end
end
This allows the simple test:
   def test_frapp
Foo foo = Foo.new
Foo.publicize_private_instance_method :frapp do
assert_equal foo.frapp, expected_frapp,
"all is not well in Foo's frapp."
end
By only exposing the one private method during the course of the test, I'm minimizing the possibility of any unintentional effects of its publicity, and thus am bit more confident than changing the character of the entire class and all of the classes from which it inherits.

I've found this to be a quite a nice surgical probe in my quest for better unit testing.

No comments: