May 21, 2016

...Learn TDD with Codemanship

Classic TDD Mistake - Writing Design-Driven Tests

Just a quick post for a grey and windy Saturday morning about a classic mistake developers make when learning TDD. Vexingly, this is something that's sometimes even taught in popular TDD tutorials. So I want to set the record straight.

People learn that the Golden Rule of TDD is that you don't declare any production code unless there's a failing test that requires it. They may misinterpret this to mean that if they plan to have a class or a method or a field, they should write a test specifically to require that.

Imagine we're TDD-ing some code that checks if a string is a palindrome (i.e., the same backwards as forwards). I've actually seen this example done in a tutorial video. The demonstrator starts by writing a test like this:

This test forces them to declare PalindromeChecker. But it's a redundant test. All we're doing here is "cheating" at TDD because we're not discovering the need for a PalindromeChecker in order to be able to check if strings are palindromes.

It's supposed to work the other way around; this isn't test-driven design, it's design-driven testing, because the only reason we wrote this test is that we wanted to declare a PalindromeChecker class.

TDD should focus on the work that our objects do, and the classes and methods will reveal themselves as places to put that work.

If we started with this test instead:

...then what's explicitly asserted in the first test is now implicitly required for this test to pass. If PalindromeChecker doesn't exist, then the code won't compile. If we don't instantiate PalindromeChecker, calling isPalindrome() will cause a null reference exception.

Most importantly, I decided I needed a method that checks if strings are palindromes - which I gave a (hopefully) self-explanatory name - and I decided to attach that method to a class that also has a self-explanatory name, purely so I could test if "abba" is a palindrome.

More generally, don't write tests about design structure: "There should be a class called Zoo, and it should have a collection of enclosures, and a keeper, who has a name." etc etc. Start with "What does this zoo do? What are the rules when it does it?", and the structure will reveal itself.

Posted 4 years, 6 months ago on May 21, 2016