What is Test Drive Development? ๐
- It's the process of letting tests lead our development.
- Write a test that fails and then write the production code that will make it pass.
How To Name a Test? ๐ง
- I like to follow the Given_When_Then format.
- We specify three things -The conditions predefined for the test (Given) -The action that will be tested (When) -The result we wait for (Then)
TDD Rules โ๏ธ
According to Uncle Bob, TDD has three rules
You are not allowed to:
- Write any production code unless it is to make a failing test pass.
- Write any more production code than it is sufficient to pass the single failing test.
- Write any more unit test code than it is sufficient to fail.
- Compilation failures are considered failures.
Confession ๐คญ
- I don't follow those rules 100% of the time.
- Sometimes I write more production code than what makes the test pass, sometimes I write code without tests.
- It's human nature I think, we can't follow the rules all the time
Code Example For a Calculator ๐งฎ
Let's look at the requirements
- The method can take 0, 1 or 2 numbers as a string, and will return their sum (for an empty string it will return 0)
๐ First of all, let's write the code to handle the empty string case
@Test
public void givenEmptyString_Return0(){
CalculatorService calculatorService = new CalculatorService();
int result = calculatorService.getSum("");
assertEquals(0, result);
}
When you write this code, it will give you a compilation error because CalculatorService
and its getSum
method don't exist.
So, we create the service and its method and write a simple logic to return 0 on empty strings
public class CalculatorService {
public int getSum(String s) {
if (s.isEmpty())
return 0;
else
return 1;
}
}
Note that the 1 in the else statement is an arbitrary value used to avoid compiler error since we have to return a value from the method.
๐ Now, let's write a test to handle strings with 1 number
@Test
public void givenAStringWith1Number_ReturnIt_WhenCalculateSum(){
CalculatorService calculatorService = new CalculatorService();
int result = calculatorService.getSum("5");
assertEquals(5, result);
}
When we first run this test, it will fail because the returned value is 1. So let's make it work
public int getSum(String s) {
if (s.isEmpty())
return 0;
else if (s.length() == 1)
return Integer.parseInt(s);
else
return 1;
}
๐ Next, let's write a test to handle strings with 2 numbers
@Test
public void givenAStringWith2Numbers_WhenCalculateSum_ThenReturnSum(){
CalculatorService calculatorService = new CalculatorService();
int result = calculatorService.getSum("69");
assertEquals(15, result);
}
This test will fail because 1 doesn't equal 15. duh!
Let's make it work
public int getSum(String s) {
if (s.isEmpty())
return 0;
else if (s.length() == 1)
return Integer.parseInt(s);
else
return getSumForMultipleNumbers(s);
}
private int getSumForMultipleNumbers(String s) {
return Arrays.
stream(s.split("")).
mapToInt(Integer::parseInt).
sum();
}
Celebration ๐ฅณ
We've just applied TDD to program a really simple calculator.
Further Readings ๐จโ๐ซ
โ How To Unit Test Like a Pro
Top comments (0)