Test-Driven Development: A walkthrough using Java
is not just about Testing.
TDD
Better structure in code
Reduce time debugging
Make a plan, then code
TDD
Best Practices.
Naming Conventions :
Place Test and Implementation in different packages.
Use descriptive names for methods.
public final void whenMoreThan2NumbersAreUsedThenExceptionIsThrown() {
StringCalculator.add("1,2,3");
}
Test
Processes:
Development Practices:
Write simplest code to pass the test.
Assertions goes first.
Minimize assertions in each test
A practical example:
List of requirements to make a String Calculator:
Requirement 1:
The method can take up to 2 string numbers, each one separated by a comma(,)
class CalculatorTest extends groovy.util.GroovyTestCase {
@Test(expected = RuntimeException.class)
public final void whenMoreThan2NumbersAreUsedThrowException() {
StringCalculator.add("1,2,3");
}
@Test
public final void when2NumbersAreUsedDoNotThrowException() {
StringCalculator.add("1,2");
Assert.assertTrue(true);
}
@Test(expected = RuntimeException.class)
public final void whenNonNumberIsUsedThenExceptionIsThrown() {
StringCalculator.add("1,X");
}
}
Test:
The method can take up to 2 string numbers, each one separated by a comma(,)
public class StringCalculator1 {
public static final void add(final String numbers) {
String[] numbersArray = numbers.split(",");
if (numbersArray.length > 2) {
throw new RuntimeException("Up to 2 numbers separated by comma (,) are allowed");
} else {
for (String number : numbersArray) {
Integer.parseInt(number); // If it is not a number, parseInt will throw an exception
}
}
}
}
Implementation:
Requirement 2:
@Test
public final void whenEmptyStringIsUsedThenReturnValueIs0() {
Assert.assertEquals(0, StringCalculator.add(""));
}
Test
public static final int add(final String numbers) { // Changed void to int
String[] numbersArray = numbers.split(",");
if (numbersArray.length > 2) {
throw new RuntimeException("Up to 2 numbers separated by comma (,) are allowed");
} else {
for (String number : numbersArray) {
if (!number.isEmpty()) {
Integer.parseInt(number);
}
}
}
return 0; // Added return
}
Implementation
Text