A hitchhiker guide to Test Driven Development (TDD)
Test Driven Development (a.k.a TDD) is one of the most intriguing feature of eXtreme Programming(XP) family. It has its own share of critics and followers.
However, there is a general consensus that TDD, if followed, produce codes with better unit tests with (probably) reduced bugs.
Despite the popularity and the general consensus about benefits of TDD, it’s still considered as an extra curricular coding activity than a mainstream one. There might be various reasons for the same, but as a developer I found that the most obvious reason is the misconception about the core principles behind TDD and how to use them.
So I’ve decided to decode the TDD for the benefit of people willing to pursue it. I like TDD and practice it a lot, but holding non religious views on it.
How to start for TDD
Here are the four steps required to do the TDD which one should remember by heart
- Write “enough” failing tests before writing the production code
- Write production code to pass those failing tests
- Re-factor the code, if required.
- GoTo Step — 1
Step → 1 : Write “enough” failing tests before writing the production code
The word “enough” is subjective and depends upon individual programmers. No one can or should try to define it as something limited to a function, class etc.
If you’re comfortable in writing failing tests for complete module or components without any production code, go ahead and do it.
Also the word failure includes all types of failures, including but not limited to compile time, run time, machine access as well as infrastructure failures.
Here is a small example of sample tests you may write as part of step → 1
Step → 2: Write production code to pass those failing tests
Once you have “enough” failing tests, write code to pass those tests. For example
A common misconception is that you can’t change any of the test cases written in Step → 1 while you’re doing Step → 2. Fortunately, there is no such binding like this. Feel free to shuffle between production code and test code.
For example, when you change the name of a function or a class for better understanding, or for that matter you may choose to write some more functionality or break a function in two, you’ll have to change the corresponding tests
For example, if we change the above production code as
Then we’ll have to change the test code as the existing test code will be calling a function called
init_0 which no longer exists.
However, this also reflects the reason for writing only limited or small amount of test cases before coming to step → 2 and the reason is this.
The chances of tweaking production code is minimal (even null ), if only a small set of test cases is written and that might be the reason why people recommend not writing big bang sets of test cases before moving to write production code.
Step → 3: Re-factor the code, if required
Re-factor the code is meant for both test code and production code. Most of the time, it’s unimaginable to re-factor production code without changing the test code.
For example, if you remove a class or function as part of refactoring, you’ll remove the corresponding tests too.
For example, as refactor if we change the following in the code above
- Change the name of the class to
init_fourfunction so that it can accept two as well as four parameters.
Can you imagine the existing tests to run over here? No, not at all, you need to change the tests too to match the refactored code
Once you’re done with the Step → 3, you’re good to repeat it all over again.
How to write Test First?
This is by far the most important topic of TDD. Some proponents of TDD emphasise on this point so boldly that it looks more like a compulsion than choice.
What all is needed to write the tests first?
Before answering this, I’d like to state something which not many people in TDD world know or say, and here is the statement
It’s perfectly okay to write skeleton code before writing the tests
What the hell? Isn’t TDD means Test First?
Yes, it is, but we can’t write tests out of thin air. We need at least two thing to write the test. They are
And to come up with context and constraints, we can safely write skeleton production code. Of course, this code may change with further refactoring, but it gives programmers a starting point.
The idea and soul of TDD is to have unit tests written for all production code and it’s not a crime to write skeleton production codes for the same. For example, it’s perfectly okay to come up with a class and / or function name first as
At least, now you know the name of the class and function to be tested. You got the “Context” as well as “Constraints” to write the test cases.
However, as a matter of recommendation, please refrain from writing implementations of the same before writing the tests. Once you start writing implementation before the tests, whole purpose will be defeated.
Once you have the skeleton, you can write the tests as
And then write the implementation as
Then run it against test and then repeat the cycle of step → 1,2,3 and 4.
This is what TDD is
I hope, I was able to explain what exactly meant by TDD and how should we start writing TDD. I seriously hope that it clears all misconceptions and allow you to pursue the idea of TDD easily
Thanks for reading…!!!