A Case for Test-Driven Development

You can’t afford not to do it

John Rofrano
Nerd For Tech

--

Unit test cases in Python (Photo by author)

Test Driven Development (TDD) is the practice of writing test cases for the code you wish you had, and then writing the code to make them pass. It sounds counter intuitive. How do you write test cases for code that doesn’t exist yet? Hold that thought for a minute.

When teaching Test Driven Development, I’m almost always asked, “How do you convince someone that doesn’t want to write test cases that it’s a good idea?” I’m a big believer in not dictating to people what to do, but rather inspiring them to see the value in why we do things. I share with them, and with you, my personal journey that got me hooked on using Test Driven Development.

Why developers don’t write tests

Before we get to that, let’s understand why developers don’t write test cases.

I already know the code works.

Yes, but what about others who work on the system in the future. How will they know if they broke something? I always tell my developers working on an existing project, that the first thing you do after creating a new branch, but before you start to code, is to run the unit tests! How else will you know if you broke the code, or if by some chance, the code in the repository was already broken. Test cases are as much for the “future you” as they are for you.

I don’t write broken code

I’m sure you don’t but the environment that your code is running in is constantly changing. Packages are getting updated due to new found vulnerabilities or just version upgrades. How will you know if your code still works with the upgraded packages? You can waste a lot of time manually testing or you can run your unit tests and know within minutes if something has broken.

I have no time

You actually don’t have time not to write test cases because automated test cases save you time and stress in the long run. Test cases allow you to move with speed and agility from simple bug fixes, to full blow refactoring. This is where having test cases gives you the confidence to make code changes knowing that the test cases will uncover any change in behavior that may have inadvertently been introduced.

My Story

This is where my story comes in. I do a fair amount of backend development. I love creating services for others to use. One day I’m creating what I was sure would be an awesome service with a great API. I’m down the bowels of the code and I need some information so I add it as a parameter to the API. Then I need something else so I put that as a parameter. Eventually I needed more things so I added them as parameters too.

Now it was time to write some test cases for my code. At the time, I wasn’t following TDD. When I started writing the test cases, I suddenly realized that I didn’t have half of the information that the parameters required. My beautiful API was horrible! How could it be this bad? Where had I gone wrong?

I didn’t take the caller of my code into account because I wasn’t following TDD. What TDD does, is give you a caller’s perspective. It allows you to explore how you would want to call the code before you even write it. It has you consider, “what do I know as a caller that I could pass in and get an answer?” Having this perspective is critical to writing good code. Code is of no use if no one can call it. It must make sense from the perspective of the caller. Once I took the caller’s viewpoint, I was able to determine what the caller had that they could pass in, that I could use to give them the behavior from the service that they expected.

Spreading the passion

From that realization, I was hooked. I was determined to always write test cases for code I wish I had, to make sure that my wishes always came true.

Some time later, I was working with a member of my team, Liana Lin, who hadn’t written any test cases before. We were pair programming and we determined that we needed to take a new approach and refactor the code we were working on. After some extensive refactoring I stopped and said, “Let’s take a checkpoint and see if we broke anything” and I ran the unit tests. In less than a minute it showed us two areas of the code that we had broken. She said to me, “JR, How did you do that?”. (JR is my nickname). I said, “Do what?” She said, “You ran 382 test cases is less than a minute! It would have taken me 20 minutes to fully test this code and find the breakage”… then she said, “Can you show me how to do that?” She was sold. I had just convinced someone who never wrote a test case, of how valuable they are. We immediately stopped refactoring and I showed her how to write test cases.

From that day forward, Liana was one of the most prolific test cases writers on our project. She had seen first hand how much time it saves in the long run, and she never manually tested her code again. I had created an unstoppable test case writing machine.

Conclusion

Keeping the caller’s perspective is critical to writing great code. Let’s face it, you probably write little snippets of code to test your code anyway. Take the time to make them into formal test cases. Then whenever you find a bug in your code, don’t fix it! First write a test case that exposes the bug, and then fix the code until the test cases passes. That bug is never coming back.

Hopefully this will help you or one of your co-workers understand how valuable test cases are and how important Test Driven Development is in keeping you focused on the consumer of your code.

Acknowledgement

I want to acknowledge my good friend Wolfgang Segmuller who was one of the original DevOps Champions with me at IBM Research when we conducted DevOps Bootcamps way back in 2017. Recently, he called me up and asked if I ever wrote an article about my TDD story that I use to tell at the bootcamp. I couldn’t disappoint him and say no… so I just wrote it down now. The secret is out. Thanks Wolfgang for inspiring me and being my partner in crime all those years ago.

--

--