Published in


Test-Driven Development

Generally, when we are assigned a project or an assignment, we usually have a tendency to go for writing the code initially and believe that the tests can be written later. While doing so, we focus on writing the tests so that the code passes. In this process, most of the time, what a developer does is writes a code that at that moment he understands well, but when referring the code after a long time, he struggles in understanding it quickly. Also if some other developer is appointed to work on the project in the later stages, he/she may not be able to understand it. For an instance, if new features are to be added to the system, one has to go through the whole code and analyse the previous and new tests again from the beginning in order add the features. Thus, such a process of ‘Tests driven by Code’ might increase complexities in the system and also may consume a lot of time in the process of development.

To tackle all such issues in the development of a project, Test Driven Development (TDD) comes into the picture. The goal of TDD is to write a clean code that works. The benefit of test-driven development is that it makes the developer focus on the requirements before writing the code. It mainly focuses on writing the tests even before a piece of code is written. The TDD provides a perfect balance between coding, testing (writing unit tests) and designing (refactoring).

TDD suggests to add a test as soon as a new piece of logic is added to a particular function, even if the implementation of the function is not complete. There are three main rules to be followed in TDD; writing a test and running it to see it fail; making the test pass; making incremental changes to improve the design of the code.


Following is the test-driven development cycle:

1. Writing a test that will fail:

The first and obvious step is to create a test. This test should be the simplest one, testing a very specific aspect of the feature. On creating the test, make sure that it fails. Thus, as the test fails, you can be confident that the test is useful, and will be beneficial once the necessary code is written to pass the test.

2. Write a code to pass the test:

On confirming that the test fails, now a code is to be written to pass the test. While writing the code, you should not write any additional or unnecessary code that goes beyond the scope of the test. You should focus on writing the simplest code that allows the test to pass. Once the code is written make sure that the test passes.

3. Refactor:

Refactoring is basically making incremental changes to improve the design of the code. The importance of refactoring is to focus on simplifying the code. for instance, while writing the code to make the test pass, it may have introduced some duplications or inconsistencies. Thus these problems should be located in the code and thus the code should be simplified. While refactoring, frequent re-running of all the tests should be done to make sure you haven’t accidentally introduced any additional bugs.


Problem Statement:

Create a function that takes a string as an input, and outputs the number of vowels in that string.


· Consider the simplest scenario like “an empty string” and write a test for it as shown below:

public class VowelCounterTest {
public void shouldCountZeroWithAnEmptyString(){
assertEquals(0, new VowelCounter().count(“”));

· Run the test and see it fail.


· Here is the code we wrote to make the test pass.

public class VowelCounter {
public int count(String string) {
return 0;

· Here we are supposed to write the simplest code possible. Thus, here the simplest possible solution to make the test pass is just returning zero.


· On writing a complete solution, see if there is any scope for improvement in the code.

· If you had come up with things you can improve in the code, go ahead and make those changes.

· Run the tests again and see that they continue to pass.

· In the above example, as you move further by adding more tests, you’ll find the scope for refactoring.

· On completing this step, consider a more complex test like ‘A string containing both upper and lower case characters’ and start over with Step 1.


· Thus by following the TDD, on adding a new feature, immediate feedback is obtained on whether the design needs to be changed or not.

· As TDD focuses on writing tests first and then the code to pass it, it is found that this approach has drastically reduced the need for debugging.

· When the project is developed using TDD, then even if there are any features needed to be implemented in a later stage, it becomes very easy to understand the previous implementation and to implement the new features

· The code developed is flexible and modular.

· Documentation becomes easier as unit tests are self-documenting and easier to read and understand. TDD suggests always descriptively document the code.

· TDD gives us the liberty to keep evolving the system’s design without breaking the code.

To learn more on Test Driven Development, refer to the link provided below of the course titled ‘Test Driven Development — Complete Guide’ on UDEMY.

Udemy TDD Course:



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store