4 min read

Why I practice TDD and how it can help you too

I always knew that testing was important, but I neglected it for a long time. During my studies, the subject was unfortunately given far too little attention and there was also a lack of practical relevance. However, as I gained more professional experience, I learned that I always have to expect a certain error rate and unpredictable bugs. TDD is crucial for recognizing these at an early stage and achieving good productivity in the long term.

Software Testing at SAP

During my time at SAP and in the first team I was in, we wrote no or very few unit tests (I definitely didn't). The focus back then was on end-to-end testing (E2E). Later, in a different team at SAP, I came into contact with tests and test coverage for the first time, but still had little intrinsic motivation to write any. I saw it more as a necessary evil, with the idea of writing a test after the actual function.

Software Testing During Self-Employment & Open Source

With the launch of my company LemonHeap GmbH and the LemonSpeak product, I then wrote unit tests occasionally and depending on their importance, but I was still very far away from a TDD (Test Driven Development) approach. LemonSpeak was a one-man show. Hence the question: Why write so many tests if I'm the only one developing the software anyway? My opinion at the time was that tests only have a right to exist for software that several people are working on. Then the advantage is that you don't have to completely understand the overall construct, but only the individual components that are changed or added. The existing tests then check whether errors occur and, in the case of a “pass”, allow the conclusion to be drawn that there are no side effects.

I changed my opinion towards the end of LemonSpeak, when I looked back and assessed how much support was caused by bugs and whether I could have avoided this through testing. You guessed it: most of it could have been avoided. At that time, I also got more involved with TDD and familiarized myself with the topic.

The second moment I realized the importance of tests was when I made my first open source contribution to Pydantic Logfire. The first pull request was without tests, the maintainer told me to add tests and shortly after the code was merged, it caused another bug for a user. That was a real eye-opener for me, because if the tests had been more thorough, it would have been found. The user wouldn't have opened a bug report, the maintainer wouldn't have pointed it out to me and I wouldn't have had to spend time fixing the bug again. Three people were directly affected. For me, avoiding this has something to do with professionalism.

How Does TDD Work?

TDD stands for Test-Driven Development and is not new: the concept was introduced by Kent Beck at the end of the 1990s. The idea is as follows:

  1. You come up with a list of test conditions.
  2. Take the first one from that list.
  3. The third step is to write the test condition before the actual function and think about when the result is a “pass” and when the result is a “fail”.
  4. Now write your function so that the test is fulfilled.
  5. Optionally, in the next step, you can think about the abstraction and design of your code and refactor it. That was already one cycle. If you still have test conditions left, the cycle starts again from the beginning (goto #1). Iterations are part of TDD, because you want your function to fulfill further test conditions.

This cycle is also known as the red-green refactor. Red because your assert fails first. Congratulations if you are at Green, because then your test has received a pass. The refactor step was difficult for me to understand at first. Mainly because I took it for obviously. Once you have a green, you can refactor your code and structure it differently. Be it a pattern or a different approach. That's entirely up to you. The nice thing about it is that you have the assurance that everything will still work, as your previous tests still have to run. Here is a small visualization of TDD:

Iteration Cycle of TDD

In my opinion, while TDD is great in theory, it needs a certain amount of repetition in practice to become routine. Martin Fowler has written a very good introduction to TDD. Even more interesting, however, is the article “Canon TDD” by Kent Beck himself, in which he clears up some misunderstandings and misconceptions about TDD. Due to the negative examples that Beck points out, the information content is very high.

In my opinion, the advantage of TDD lies not only in the increased reliability of the software, but also in the fact that I have to think intensively about how I design the interface to my code and the function (keyword: differentiation between interface and implementation → good design). To illustrate this: When I write a new function, TDD forces me to define the interface first, otherwise I couldn't even test it.

Conclusion

There are many books, such as "Clean Code" or "Practical Engineer", that address the fact that high test coverage is a must. And although I now see the necessity, without the TDD approach I would find it difficult to write the tests afterwards.

Because as soon as I have developed a feature or fixed a bug, the next issue is already waiting around the corner. Unfortunately, writing a test for the previous component is often sink into oblivion. It's like tidying up at home: if something is lying around, it's tidier in the end if you tidy it up straight away instead of postponing the task.

How much and how intensively you test naturally depends on the importance of the software. But testing has become indispensable for professional software. Whether this involves unit tests, integration tests or end-to-end tests depends heavily on the architecture, the goal and the aforementioned importance of the software.

Meanwhile, I have become very familiar with TDD. In my current work, I have already been able to use it to prevent bugs during development, which just feels great. Nevertheless, the topic is still new territory for me in this intensity. As I am learning a lot in this area myself, I would like to share this knowledge with you in the next few articles.

Have you made good experiences with TDD or do you see it differently? Do you know any good resources? Let me know!