TDD is also referred to as Test First Development. In both names, the key aspect is that the test must be written before the application code. Robert C. Martin, affectionately called "Uncle Bob" by the developer community, has created The Three Laws of TDD. They are as follows:
- You are not allowed to write any production code unless it is to make a failing unit test pass
- You are not allowed to write any more of a unit test than is sufficient to fail, and compilation failures are failures
- You are not allowed to write any more production code than is sufficient to pass the one failing unit test
You can learn more about these laws at http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
By following these rules, you will ensure that you have a very tight feedback loop between your test code and your production code. One of the main components of Agile software development is working to reduce the feedback cycle. A small feedback cycle allows the project to make a course correction at the first sign of trouble. The same applies to the testing feedback cycle. The smaller you can make your tests, the better the end result will be.
Note
For a video on Agile, check out Getting Started with Agile by Martin Esposito and Massimo Fascinari (https://www.packtpub.com/application-development/getting-started-agile-video).
The original approach to TDD has caused some confusion over the years. The problem is that the principles and approaches just weren't structured enough. In 2006, Dan North wrote an article in Better Software magazine (https://www.stickyminds.com/better-software-magazine/behavior-modification). The purpose of the article was to clear up some of this confusion and help to reduce the pitfalls that developers fell into while learning the TDD process. This new approach to TDD is called Behavior Driven Development (BDD). BDD provides a structure for testing, and a means of communicating between business requirements and unit tests, that is almost seamless.
It's difficult to start any journey without a goal in mind. There are a few tips and tricks that can be used to help get you started in TDD. The first is red, green, refactor.
We already discussed writing a failing test before writing production code. The goal is to build the system slowly through a series of tiny improvements. This is often referred to as red, green, refactor. We write a small test (red), then we make it pass by writing some production code (green), then we refactor our code (refactor) before we start the process again.
Many TDD practitioners advocate an It Exists test first. This will help determine that your environment is set up properly and you won't receive false positives. If you write an It Exists test and don't receive a failure right off the bat, you know something is wrong. Once you receive your first failure, you're safe to create the class, method, or function under test. This will also ensure that you don't dive in too deeply right off the bat with lines and lines of code before you're sure your system is working properly.
Once you have your first failure and the first working example, it's time to grow the application, slowly. Choose the next most interesting step and write a failing test to cover this step.
At each iteration, you should pause and evaluate whether there is any cleanup that can happen. Can you simplify a code block? Perhaps a more descriptive variable name is in order? Can any sins committed in the code be corrected, safely, at this time? It's important that you evaluate both the production code and the test suite. Both should be clean, accurate, and maintainable. After all, if it's such a mess that no one would be able to make head or tail of it, what good is the code?
TDD will also help you avoid what writers often call writer's block and what we're calling coder's block. Coder's block happens when you sit down at the keyboard in an attempt to solve a problem but don't know where to begin. We begin at the beginning. Write the easiest, simplest test you can imagine. Write It Exists.
We're professionals. We want to do a good job. We feel bad if someone finds fault with our code. If QA finds a bug, it makes us sad. If a user of our system encounters an error, we may cry. We should strive to deliver quality, error-free code and a fully functional, feature-rich application.
We're also lazy, but it's the good kind of lazy. We don't want to have to run the entire application just to validate that a simple function returns the proper value.