A Quick Cost/Benefit Perspective of TDD

TDD, short for Test-driven Development, is a programming method in which any piece of runnable code results from unit tests written beforehand. A thorough application of TDD practices inevitably keeps the code coverage ratio high as every single method in every single class is generated from a unit test.

The storytelling about TDD recites that writing tests before coding helps programmers to better understand the purpose of the code being written and devise the action itself more clearly. I couldn’t agree more on the conclusions and disagree more on the premises. Let’s start from the end.

Thinking about what you’re coding, the innermost purpose of the user story and its possible repercussions on the existing, well, it does help—always. Hence, if you know the business and take the time to think, then the outcome is reasonably good even without using tests to drive your analysis and effort.

As harsh as it may sound, I’ve always found silly having to write an empty test before each method and the whole canonical procedure of TDD:

  1. Write an empty test for the method and let it just fails
  2. Add minimal code to the method just to see if it passes the test
  3. Focus on what the method has to do
  4. Adapt the test to the final form and content of the method

So, you’d say, TDD is not for me and this is yet another rant about it. Well, not exactly. To paraphrase Lord Polonius in Hamlet, I’d rather say that this is madness but there’s some method in it.

If you’re fanatic about unit tests, then you must be able to write code that lends itself to be tested. That means, code that well isolates dependencies and relies only on input data to do its job. In other words, the practice of unit tests is expected to discourage the practice of hidden dependencies in code.

Hidden dependencies are the evil and a worse yet evil when they’re hidden because developers are unaware of them.

Approaching the development process with a TDD mindset does help and is highly recommended. Practicing TDD slavishly is not a great statement per se, but it may be acceptable as a personal style of programming.

Put another way, the benefit of TDD is not a having a huge bloat of unit tests as a bonus but the subtler fact that if your code lends itself to be tested, then it is undoubtedly of good quality. In this context, good quality means explicit mention of dependencies, layered design of functionality, clear boundaries and more structured programming. The lack of hidden dependencies makes also easier and safer any refactoring and keeps the code easier to read and understand for others.

How would you do TDD without actually writing tests?

  1. Write any method with the full list of expected parameters
  2. Return a default value of the expected type
  3. Check if you need more (or less) parameters
  4. Code and adapt return values and input parameters
  5. If you need a dependency (whether an object or just a bunch of values) add to the input list
  6. Keep an eye on data clumps and refactor as appropriate
  7. Keep an eye on groups of lines that make up an action and can be extract to a method
  8. Keep an eye on internal methods that make up a functionality and can be refactored in to an injectable class

If you code this way, any single method is testable by design. And you can write unit tests for it if someone gave you the 100% coverage goal. But there’s more: your code is clean and understandable. Even without unit tests.

Published by D. Esposito

Software person since 1992

One thought on “A Quick Cost/Benefit Perspective of TDD

Leave a comment