Sunday, February 06, 2011

UPDATED: Keep behavioural driven naming out of unit testing

Something is happening in the Test First world. There appears to be growing use of "Behavioural Driven Design" (BDD). That is, the test names in test classes are becoming sentences describing what the class should do, eg testFailsForDuplicateCustomers(). In my opinion this trend is damaging the effectiveness of Test First Design in the field.

Don't get me wrong - I think the fundamental idea behind BDD is sound. But I am finding that this kind of naming approach for unit tests is seriously detracting from the "code is the documentation" ideal. If you have a class with method "X", you should expect a test method "testX" that defines the method's contract. If the method's contract is more complex, you might expect to see a set of methods like "testX_NullInput" etc. This approach documents the class pretty damned well in my experience.

Now image the same class being tested by something like "testFailsIfCustomerIsNull". What fails? What input? Have I tested method "Y"? But method "Z" shouldn't fail if Customer is null! You end up doing some serious analysis to work out what is going on which fundamentally defeats the object of the tests replacing design documentation. Using BDD test naming here is actively obfuscating how the system works at a class level, not clarifying.

(Note - nothing that I am suggesting excuses obscure method naming. A method should do what it says and say what it does, with the detailed clarification of the contract being defined in the tests. All I am saying is that there should be a simple, obvious mapping between methods and the tests that verify their behaviours)

Where BDD comes into its own is when defining interactions. Integration tests that check the interaction of closely cooperating classes benefit hugely from descriptive naming. Also User acceptance tests reap huge rewards from the approach since the tests are described in business language that allows a Customer to understand what is being tested. Yes, use BDD naming in these cases because it does help.

Just keep it away from Unit Tests!

UPDATE: I wrote this article back in 2007. It's now February 2011, and a lot has happened. Since then those fine chaps Nat Pryce and Steve Freeman have written their excellent Growing Object Oriented Software with Tests book showing how it should be done. Jason Gorman's observations on two distinct TDD styles also filled in some gaps I had missed. Also, the whole "Software Craftsmanship" movement has moved understanding forward a huge amount by daring to ask questions and clarify.  

And then there was the clincher, the tool that stuck everything together for me, giving the penny a clear path to drop with a loud Clang! The IntelliJ TestDox plugin. Suddenly the BDD approach to unit tests makes much more sense, to me at least, so I am happy to admit that my views expressed here have now changed. Or at very least, softened a huge amount. I now tend to use behaviours rather than specifics to define class level behaviour.

Which just goes to show what can happen if you keep an open mind and try different approaches.

No comments: