Ask a dozen developers what TDD means to them and you’ll most likely get the answer “writing the tests first, then write code that makes them pass”. This being the generally accepted definition as it makes sense in theory, but in practice is inconvenient, and more often than not impractical to pull off. This can leave a bad impression and pushes developers away.

However, this isn’t what TDD is all about, and shouldn’t be seen as the go-to definition. Think of TDD as requirements driven development with verification. The test definitions are what matter most, they’re derived from the requirements and are what should be written first, not the tests themselves.

The following comes from an article I read recently (unfortunately I can’t find the original) and it really helped understand how to approach TDD.

  1. With pen and paper, write a list of test cases, as many as you can think of. Every reasonable input with their expected outcome as derived from the requirements.
    • It might be that when writing these requirements, you find gaps or contradictions. Solve these, come back and rewrite any that have now become outdated.
  2. Write the signatures of these tests, keep them descriptive to exactly what the requirement is, when that then this - and force them to fail.
    • It may be worth adding a placeholder for the input data required that you can fill in later.
  3. Begin writing the code with the requirements in mind. As you solve particular requirements, add the necessary code to the test case to make it pass. The signatures should not change.
    • As you write more code you may find that tests are becoming contradictory or code paths not accounted for. This is not a flaw in the tests but in the original requirements. Raise this with whoever needs to know, update the specification and go back to step 1, writing out any new test signatures that need adding, removing obsolete ones.

The requirements inform the test, the tests drive the development and the development refines the requirements. This loop ensures all paths and accounted for, all requirements assigned and all development tested.