For this post, I wanted to take a look at Test-Driven Development (TDD). What is TDD? TDD is a test-first technique in software development, that means we write our tests first then we write our actual production code. The TDD approach relies heavily on the repetition of a very short development cycle while following The Three Laws of TDD.
Always remember the goal of TDD is the make our code cleaner and simpler.
Before we get into the good bits I think it might be worth quickly going over the way software has generally been written and identify some of the flaws. It is more common to see production code written first with the unit tests being more of an afterthought, still it less common today than say 20 years ago. However, we still have the same problems, when our codebase does not contain reliable extensive tests we are hesitant to make any changes. Especially in those instances where we don’t have any real confidence in the code itself, perhaps because we inherited it, because it was rushed. By following a TDD approach we can make changes, for whatever reason, with more confidence.
Enough with looking back, let’s look forward…
We’ll start with the Three Laws of TDD, they are:
- First Law: You may not write production code until you have written a failing unit test.
- Second Law: You may not write more of a unit test that is sufficient to fail, and not compiling is failing.
- Third law: You may not write more production code that is sufficient to pass the currently failing test.
If you follow these rules you get locked into the development cycle mentioned above. Uncle Bob has mentioned in his books and videos that this cycle can be from 30 seconds to a minute and there have been others that have said it could be longer. I find it varies depending on the complexity of a given situation but it is certainly within the definition of short. Essentially it looks like this:
The above shows a visual representation of the development cycle we get into by following the TDD approach, we:
- Write our test
- Run our tests
- Make code changes
- Add required production code
- Refactor code
- Run our tests
We can see that any failing test means we ‘Make Code Changes’ and any passing test we ‘Write a test’. That’s it, that’s the cycle we get ourselves into and that’s the cycle that gives us that confidence I mentioned before.
By working this way we end up with a massive suite of tests that (providing the tests themselves are of good quality) mean we can refactor, extend, or update our production code we confidence if/when we break something we find out immediately and can fix it.
I’m not going to go into any detail on the tests themselves as I find that is two different topics or at least a topic I want to expand into in the future. So while we can follow TDD it won’t be as effective if our tests are of poor quality.
Finally, from my experience, I have found following a TDD approach to my development activities has given me far more confidence in my code for two reasons. The first is the likelihood my code will work as expected once released. The second is that I can go in and make changes as needed without the concern that I’m touching something fragile and once a change is made the whole system might come crashing down around me. I’d recommend if you don’t use TDD that there are plenty of really good resources out there for you to check out, two I’d recommend are Pluralsight, there are a lot of useful courses available through them and Uncle Bob’s Clean Code book, Chapter 9 is all about unit tests.