Test Driven Development (Part 1) — Why I adopted it and my journey so far
I am so excited to write my first technical blog and I have chosen a topic that I am extremely fascinated about, Test Driven Development (TDD). I recently learned about TDD and at first, I found it extremely difficult to wrap my head around. Gradually I started to understand TDD and now I am practicing it when I write any code. Given that it is a vast topic and it takes quite a bit of time truly to appreciate the importance of TDD, I am going to break this blog into 2 parts. This blog is the first part of my journey to learn TDD.
It is said that to understand and realize the value of something one must first understand the Why and the What of it. The How simply follows the Why and the What. This blog is going to focus on the Why and What of TDD. In part 2 I will talk about the How of TDD.
What is TDD?
Test Driven Development or Test Driven Design is an approach for building software that specifies and validates what code will do by driving it through tests. The simple concept of TDD is to write and correct the failed tests before writing a new code (before development). This helps in avoiding duplicate or wasteful code as we write a small amount of code at a time to pass tests. In short, it’s like having a safety net before jumping.
When we start with TDD, we don’t know what final production code will look like. We do not know the name of classes, methods, and variables. This means that TDD emphasizes on what first before answering how.
With TDD we get to evolve an elegant solution along with the evolution of the requirements. While at first, doing this feels difficult, over a period of time it becomes quite easy to build large applications.
This generally happens from the “red-green-refactor” cycle.
Following steps define how to drive your development through tests:
- We start with adding a test that defines your requirement (and fails because of a lack of implementation)Run all tests and see if the new test fails (Red stage)
- Write the minimum code to pass that test (Green stage)
- Refactor the code
- Repeat
Why is TDD Important?
So now to understand the why of TDD, let’s first think of a development scenario without TDD i.e. one where we write code first and tests later.
Once I have written the code, we are going to test it. I will go method by method, covering different scenarios such as happy, sad paths. Great! But wait, did I cover all the scenarios?
So it’s the time we start thinking about how to fail the code that I wrote by writing some tests.
I found one, I added a test. It started to fail while adding code to cover the failing scenario I wrote more code. I will likely touch code which is beyond the direct scope of the scenario we originally started to cover and we probably ended up duplicating code and in the process, we added additional code that does not have any test and I forget to add a test for the additional code.
What I think is the most complex part of this is about when we should stop this endless cycle…
There might be a lot of cases that we think of when we are writing a test rather than writing the code first.
And suppose if a new member joins a team, writes a piece of code that is appropriate, but causes some issues altogether. How will other people in the team get to know about the changes and identify dependency quickly if no one sees any failure?
The scariest thing, if this code goes to production and the scenario occurs which was not handled properly or wasn’t thought of! This causes many problems and a lot of stress for the whole team.
Now let’s look at the scenario where I wrote the tests first.
In this approach, I start thinking about all the scenarios about the requirement in hand and what all scenarios code should handle. I start with the simple test, It fails. We add code to make it pass and then refactor it.
Slowly I am covering all the possible scenarios because it is the brain that starts thinking in the direction of scenarios and actual requirements that my code should be implementing.
In simple words, we are here focusing on the WHAT part first and then the implementation i.e the HOW part of it. And this journey the code starts to evolve driven by the tests instead of tests driven by the implementation of the code.
Not only that but when a new member joins a team when they add any new code that disturbs other parts of code, this is immediate feedback and visibility as the test will fail instantly, this is something that I experienced in the team when I was new, the tests stopped me from doing unwanted mistakes. The tests not only were safety nest they also served as good documentation for the new member joining the team. Just going through the tests and the scenario will give an insight to the person about the product.
And the most important thing is that you know exactly what is covered and when to stop adding tests.
Whenever I have to add any new feature, it begins with a red test and then implementing it. This I found to be a more natural way of development. It helps, in meeting the requirements with a good implementation along with decent developer-centric documentation.
Yes, I found it difficult sometimes when I refactor the code that leads to the other tests fail.
But, if we know how to use the IDE and its shortcuts and the approach, It isn’t a big deal.