TDD — The Tests that Bind
“We test now?” “We test now.”
This article is written as a part of Individual Review competency for Software Projects course 2020 at Faculty of Computer Science, University of Indonesia.
Test-Driven Development (TDD), also known as Test-First Programming, is an approach in software development that dictates its developers into creating tests in form of code (usually test function) before they begin working on the implementation code. Put simply, developers should create tests first before proceeding. That’s why it’s called Test-Driven or Test-First.
“But isn’t it simpler if we just test the program by hand? Why bother creating more code just to test”
While it’s subjectively more convenient to test any functionality of the software/program by hand, it could also become tedious if we find a specific mistake (infamously known as program bug), fix it, and retest the program again. Imagine that repeating scenarios for a complex software… To save time, we should write the tests in form of code with any testing tool of our choice (I won’t be discussing it in this post) and run them automatically. Using said approach, we can get quick feedback if any test fails so we know where to look and plan ahead our next move.
Okay, so we know why automated testing is important. But is using automated testing in any form is already TDD? No if we create the tests after creating the real implementation. Tests should go first, which brings us to the cycle of TDD, explained below.
As we can see, the TDD cycle depicted above has three repeating steps. Where should we proceed first? The red one. Below is the explanations for every step:
- The Red Zone (Test). This step requires us to plan and think on what functionalities we will implement. And what should we write first? Of course, the tests. We write the tests, while keeping what functionalities will be implemented in mind. The tests should fail because, of course, no implementation code have been written yet at the time. What kind of tests should be written depends on specific cases, whether it’s Unit, Integration, System, etc.
- The Green Zone (Implement). After creating the required tests for our would-be functionalities, we proceed on writing the implementation code. The objective here is to pass all the tests written in the previous step. If all goes well, all the tests should pass (green is used as color cue, hence this is called the “green” step). Else, rewrite the implementation code until all the tests pass. In this step, we need not to think too much on how the implementation code will look. It’s reasonably okay if the code may look imperfect. Focus on making the tests pass.
- The Blue Zone (Refactor). This step can be optional, depends on the state of our implementation code. This is related to the need of making our code “clean”, effective, readable, and easy-to-maintain. If in the previous step we committed some “sins” by making our implementation code look “ugly” in order to pass all the tests, we cleanse away our sins in this step by refactoring. If no “sins” were committed, we can safely skip this step.
- Repeat the Red Zone if there are new functionalities waiting to be implemented. This is what makes it a cycle, of course.
At first glance, it seems a big deal for us on having to create tests beforehand. But TDD has its merits. It forces us to think and act carefully on how we make our program and can lead to minimizing mistakes or bugs along the way.
TDD Implementation in Software Projects Course
Below is the TDD implementation that I’ve been following in working on TahfidzIsMe website.
In this scenario, I had a task in making a custom user model for the Django-based back-end application.
The tests defined above can be thought as “unit” tests because every test only revolves on one class/unit, the UserAccount class/model.
Each test defined above focuses on one thing, described by their function name. At the time, I haven’t implemented the custom user model code. So I was expecting a RED on the GitLab pipeline.
The next step was to implement the required code in order to pass all those three tests.
After pushing the commit to the GitLab…
That pipeline status turned GREEN, meaning that the implementation was correct against the tests.
At the time I didn’t need to to the Blue Zone/refactor step, because all the logic that need testing were already encapsulated in the AbstractUser class and there were no needs for refactoring.
On another occasion I also had a task in implementing an endpoint so the client (front-end) would be able to post register new selection data. The tests involved more than one module (views, model, and url configuration) so those tests were categorized as “integration tests”.
And the implementations below…
This wraps up the post, folks. I hope you find it useful :)
See you next time!
Originally published at https://www.linkedin.com.