Debugging With TDD
Humans are bad at repeating the same steps. Computers are great at it. That's why I debug with tests.
What is TDD?
TDD is a discipline that encourages you to start by writing tests instead of the functionality itself. You first write a simple test that validates the business requirement, and then you write the functionality to make that test pass. This leads to the TDD mantra: Red, Green, Refactor.
What is debugging?
Debugging is the process of finding out why your software is not working as expected, and fixing it.
I'm writing this article for people who write and debug code all the time. And I will try to convince you to debug with TDD instead of guessing, brute forcing, or relying on your memory throughout the process.
So you finished writing a great application, and now it is in production. You have plenty of happy customers. And suddenly, you get a bug report saying that some functionality is not working as expected. Neither you nor anyone in your team changed anything recently, and no one has any idea what led to the problem.
It is time to debug!
Depending on the bug and how complex your system is, we can divide the debugging process into 4 steps.
Understand the system and the problem at hand
Without a proper understanding of what you are dealing with, you will end up either fixing something else or making the system worse. You should understand what the problem is and how you can reproduce it. You must know the expected behavior of your system before you even start reading the code.
Make it fail
When you understand the problem, it's time to make it fail consistently. If it sometimes fails and sometimes doesn't, then you didn't make it fail yet. Some condition is still missing, and you need to find it. This is a key point in this article, and we will talk about it in more detail below.
Investigate
There are many strategies you can use to investigate issues. One of them is the "5 whys", which starts with the result and goes backward by asking why.
Fix it
After investigating and finding the root cause, you fix it. Then make sure the problem is really fixed: apply your fix and try, then remove your fix and try again. Your trials must be reliable and repeatable.
If you are interested in debugging and want more, you can read this article about debugging.
Test driven debugging!
Why is it a big deal? Can't we debug the usual way, by trying and looking at the failure?
Of course, we are free to use any debugging or investigation strategy. The decision depends on what we know about the issue, the system we are working with, and how critical the problem is.
I will not say that TDD is a tool for everything and you have to use it all the time. What I want to show is when to use it and what benefits it brings you.
Do not use TDD if you are 100% sure what the problem is, you are 100% sure what the solution is, you know everything about the system you are working on, and the fix is so time critical that it needed to be deployed yesterday.
In all other cases, it is better to use TDD. Writing a test before looking into the implementation needs knowledge about the functionality you are investigating and about the system you are working with. It also needs a complete understanding of the steps to reproduce the bug. All of this makes sure you are not solving the wrong issue, and that you are solving the right one correctly.
And back to the second step of debugging, make it fail consistently. Humans are unreliable. You cannot guarantee that a person does something the same way multiple times. We are not built for that. Neither our memory nor our brain can repeat the same process in the same way every time!
So to repeat the same issue again and again and watch it fail, you need a computer. Computers are reliable, they have accurate memory, and they don't think. They consistently do whatever we tell them to do.
TDD will make you faster, because there is no chance you miss a requirement, unless you don't know about it.
- With TDD, you will never be too lazy to start from the beginning every time.
- With tests, you can control the system state, like time, data, and everything else.
- With TDD, when you solve a problem, you are 100% sure you solved it, unless you didn't understand it in the first place.
- Tests are repeatable, efficiently and reliably, with no extra effort.
All of the above makes sure your solution works now and will keep working in the future. So you don't need to waste extra time on manual regression testing with every line of code you add.
Final words
In my experience, TDD saves a lot of time, and not doing it will hit you later. Tests are simple, and writing them doesn't take a lot of time. And if you need a lot of time to write a test for some feature, it means you don't fully understand the feature or the system you are working with. If you have another opinion or want to discuss this more, contact me on X @salem_hsn.

If this was useful
Telc German B1 Exam Success Kit (20/80 Rule)
The 20% of German that keeps showing up in the telc B1 exam. Learn it first and walk in already knowing what to expect. €25