Test Driven Development

(Test Driven Design)

This is one of the strangest-sounding practices to come out of the world of clean code and the implementation of practices derived from the folks who brought us the Agile Manifesto. It sounds crazy to non-developers. It makes perfect sense to developers. Here’s how it goes.

Write a failing automated test before changing any code. Test-first programming addresses many problems at once:

  • Scope creep — It’s easy to get carried away programming and put in code “just in case.” By stating explicitly and objectively what the program is supposed to do, you give yourself a focus for your coding. If you really want to put that other code in, write another test after you’ve made this one work.
  • Coupling and cohesion — If it’s hard to write a test, it’s a signal that you have a design problem, not a testing problem. Loosely coupled, highly cohesive code is easy to test.
  • Trust — It’s hard to trust the author of code that doesn’t work. By writing clean code that works and demonstrating your intentions with automated tests, you give your teammates a reason to trust you.
  • Rhythm — It’s easy to get lost for hours when you are coding. When programming test-first, it’s clearer what to do next: either write another test or make the broken test work. Soon this develops into a natural and efficient rhythm—test, code, refactor, test, code, refactor.
[1] XP Programming Explained

Robert B. Martin (Uncle Bob) puts it another way:

Over the years I have come to describe Test Driven Development in terms of three simple rules. They are:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
[2] Three Rules of TDD

Uncle Bob’s article/blog is very insightful; and has far too much truth in it to ignore. You should pop over there right now and read it. I’ll wait.

… still waiting…

Okay. Now you’re back. What did you pick up from that? I hope you picked up two major things:

  1. Everything in TDD gets tested.
  2. You can’t write code that can’t be tested.

The second reason may be the most important because (aw, c’mon, you could write this) because isolating your code sufficiently to test it renders three results:

  1. Your solution design stays discreet. You write smaller functions. You remain on topic.
  2. Your code will have 100 percent code coverage for unit tests, making collisions and problems written later come up immediately.
  3. Your code was working and releasable within the last few minutes.

TDD is often called Test Driven Design for the reason I listed above. TDD forces the developer to think clean code. You should already be thinking clean code but if you aren’t already, this practice will focus your design approach.

TDD is another OO practice that I can’t cover here sufficiently, so I’ll leave it to you to spend outside time on that study.

TDD is about design. Through TDD, an application will grow in functionality without introducing needless complexity. It’s incredibly difficult to introduce complexity if you write small tests and only enough production code to make the test pass. Refactoring, modifying the structure of the code without adding or changing behavior, should not introduce complexity, either.

[3] Practical Test Driven Development

References:

[1] Extreme Programming Explained: Embrace Change, Second Edition, Kent Beck; Cynthia Andres, Addison-Wesley Professional, November 16, 2004
[2]Three Rules of TDD
[3]Practical Test-Driven Development using C# 7; John Callaway, Clayton Hunt; Packt Publishing; February 15, 2018