Let me be honest. The first time I learned about Test Driven Development (TDD), I only thought of it as a tedious process that was just waste of time. Well, turns out that was because I didn’t understand just how essential TDD really is. After diving in deeper into TDD, I’ve realized that there is a lot more to TDD than meets the eye. In this article, we’ll be discussing just how important TDD is and how we can embrace it.
A Quick Introduction to TDD
TDD is an iterative programming cycle that consists of three main activities: creating the test, writing the code, and refactoring. We first start the cycle by writing a test. When we run the test, it should fail because we haven’t written a code implementation of the test. Next, we write just enough code that satisfies the requirements of the test. Once the code passes the test, we move on to refactoring. Refactoring cleans up your code or tests without changing the behavior of the program. After refactoring, we go back to adding another test and repeat the cycle until all the functionalities of the feature are covered and implemented.
The Importance of TDD
At first glance, working with TDD seems like doubling our workload. Having to write a test and then writing a small piece of code over and over again can be tiresome. On top of that, TDD also needs a lot of practice to get the hang of. But beneath the added workload, TDD actually offers a lot of important benefits.
Fundamentally, TDD serves as a safety net. Each time we add a change to our code, we can run our tests to ensure that our change didn’t cause any errors or unwanted behaviors. If our change did cause an error, we then know to immediately direct our attention to that certain change. This decreases or maybe even eliminates the time needed for debugging at the end. This also gives us confidence that our code will be more secure in the long run.
Another benefit of TDD is that we don’t have to start coding with a blank canvas. When writing our tests, we are forced to think about and understand the functionality we want our code to have. These tests can then guide us in writing our code. Personally, I found that writing tests is kind of like creating a blueprint for my code. The tests help me imagine the bigger picture and then when I start the coding process, I feel like I just needed to fill in the blanks.
A Few Tips
One thing to remember is that TDD doesn’t call for you to write your tests all at once. It is even encouraged to write one test at a time. As mentioned before, TDD is an iterated cycle. It builds your program over time. Each test created should also be simple and tackle only one problem. With that, each addition of a pair of test and code shouldn’t take as much time.
Another thing to take notice is that you should frequently run your tests when coding and refactoring. If you only run your tests at a certain point, it will get a lot trickier figuring out which part of your change caused the test to fail. Running your test after each change will give you a instant directed feedback.
Types of Tests
Of course, when you’re dealing with TDD, you need to know how and what kind of tests to use on you program. Some of the most popular types of test used in TDD are unit tests and integration tests.
Unit tests are tests that are conducted on small units or components of code (hence the name unit test). These tests are done isolation from the whole system and other units in order to validate the units functionality. Most of the time unit tests are done by giving the code some input and then checking to see if the output is right.
Integration tests are used to test how the program works as a system. When you want to see if two or more components can work together correctly, an integration test is the tool for you. Integration test are quite similar to unit tests where the main difference between the two is that integration tests are not done in isolation.
TDD in Practice
Now that we’ve covered the theory for TDD, it’s time to move on to some real life examples. For this example, I will be using a piece of code from my PPL class project. The functionality that I want to implement is to show owner information in a file component.
First, I created my test. Here, I made a test to see if the owner name is correctly shown in the file component.
After creating the test, I committed and pushed it onto my GitLab repository. Don’t worry when you see that the pipeline has failed! It should fail because I haven’t implemented the code that satisfies the tests.
After writing the test, I added the code implementation that passes the test requirements. My addition to the file is marked by the green background. As you can see, I only added pieces of code that are necessary to pass the test. It might seem simple, but that’s what we aim for when implementing the code: A simple piece of code that can pass your test.
Because the code has passed the test, the pipeline will pass once I push the code.
You should always refactor when needed, but for this example, my code was already very simple and didn’t need to be refactored. After I was done with the code implementation, I repeated the TDD cycle until I was done with the feature.
Introduction to Test Driven Development (TDD)
The Test Driven Development (TDD) is a software engineering practice that requires unit tests to be written before the…