2013-03-24

2. A TDD Crux: Talking to others

I've been a fan of test-driven development (TDD) since I first learned how to do it my self, and at various times during the last ten or so years I've been asked questions that pretty much sounds like "How do you test THAT?" while the asker points to some source-code. The source-code being pointed to has almost always been a tightly coupled mess without tests. And of course it's nigh impossible to test THAT without investing a significant amount of work in both refactoring and a huge scaffolding.

The Bowling kata, for example, is a well known exercise everybody who learn TDD run in to. It is simplicity itself: An internal datamodel, with simple and well defined behavior. It's "Perfekt for TDD" (If you haven't done the bowling kata yet, check it out here.) It crosses over to the "How do you test THAT?"-realm in the second it sends a signal to an external system in order to play a video of a dancing turtle every time you roll a strike. If not doing TDD, some might probably just pass the "PlayAnimation" subsystem to the BowlingGame class, and call the "celebrateStrike" method every time the player roll a strike. And voila, it is evolving in to a tightly coupled unmaintainable mess. I'm thinking of this as the first stumbling-block, the first mental challenge, when learning TDD: How to test behavior that relates to other behavior not contained in the object being implemented.

I won't dive in to mocks, stubs, fakes and the lot - there's been plenty written about that already and this is by and large a well understood problem. Still, in order to hopefully make a condensate of how to get over that hump, I do want to describe a general pattern of thought that I often apply in such scenarios, outlined in the figure below:
A less direct path
The object we are aiming to develop with TDD is Foo, and it needs to call methods on some object Bar that is not under our direct control. Instead of interacting directly with Bar, Foo interacts with it's surroundings through FooActions. Foo gets a reference to FooActions via the constructor during application setup. FooActionsBridge is a very simple implementation of something that interact directly with the Bar system, preferably only relaying method calls without actually containing any other behavior so it can be checked for correctness through quick inspection. Notice also that Foo and FooActions is bundled together in the same package. FooActionsBridge is a part of the setup of the application - so quite possibly in a third package. There is of course one obvious simplification here. If Bar is under our control,  Bar can implement FooActions directly, eliminating the need for the FooActionsBridge. In this case I sometimes like to add the FooActionsBridge first while getting Foo sorted out, then change Bar afterwards. That might be overly cautious on my part though.

So - does this help in getting over the first crux while learning TDD? Please let me know!







No comments:

Post a Comment