Na początku warto podkreślić, że Test-Driven Development (w skrócie TDD) nie jest techniką pisania testów, lecz jest techniką tworzenia oprogramowania. Jego główną zasadą jest tworzenie niedziałających testów w pierwszej kolejności, a następnie pisanie kodu celem przejścia testu. Cechuje się trzema etapami, które tworzą cykl programowania. Te etapy to:
- Red.
- Green.
- Refactor.

Same zasady programowania polegają na swojej prostocie. Zobaczmy więc po kolei o co chodzi w poszczególnych fazach.
Faza Red – zaczynamy od utworzenia nie przechodzącego testu (błędy w kompilacji testu także uważane są jako błędny test, np. gdy testujemy funkcję której jeszcze nie zadeklarowaliśmy nigdzie). Dlatego właśnie faza red kojarzy się z błędnymi testami, najczęściej takim kolorem są one oznaczane w środowiskach programistycznych.
Faza Green – kolejną fazą jest napisanie tyle kodu, aby aktualnie błędny test wykonywał się poprawnie. O tyle ważne jest to, że tworzymy tylko tyle kodu ile wystarczy do przejścia aktualnego testu. Nie twórzmy kodu nadmiarowo, to pozwala na lepszą analizę zagadnienia i pisanie prostszego kodu.
Faza Refactor – po napisaniu kodu który przechodzi aktualny test następuje faza w której dokonujemy wszelkich poprawek i usprawnień w napisanym kodzie. Ważne, że nie zmieniamy samej funkcjonalności kodu. Dla tej fazy powinno się równie tyle samo czasu poświęcać co fazom green i red, nie powinno się jej lekceważyć. Dodatkowo należy także pamiętać o refaktoryzacji kodu testów.
Znając już podstawowe zasady możemy przejść do prostego praktycznego przykładu zastosowania TDD. Wyobraźmy sobie, że w istniejącej klasie Math tworzymy nową funkcję która jako argument przyjmuje jakąś cyfrę, a zwraca String stwierdzający czy liczba jest parzysta czy nieparzysta. Nazwijmy funkcję tę funkcję checkNumberEvenOrOdd(). Zgodnie z pierwszym etapem tworzymy nie działający test.
@Test
void shouldReturnEvenWhenNumberIsEven() {
//given
Math math = new Math();
//when
String result = math.checkNumberEvenOrOdd(2);
}
I tutaj mamy pierwszy niedziałający test. Aby test był pozytywny musimy dodać funkcje do klasy Math.
public String checkNumberEvenOrOdd(int number) {
return null;
}
Jak widać napisaliśmy jak najmniejszą ilość kodu, aby przejść test. Nie mamy co refaktoryzować w kolejnym etapie, więc zakończyliśmy pierwszy cykl programowania. Następnie dopisujemy do testu sprawdzenie i zaczynamy kolejny cykl programowania błędnym testem.
@Test
void shouldReturnEvenWhenNumberIsEven() {
//given
Math math = new Math();
//when
String result = math.checkNumberEvenOrOdd(2);
//then
assertThat(result, equalTo("Even number"));
}
Musimy teraz dodać funkcjonalność, która zwróci nam „Even number” prz parzystej liczbie.
public String checkNumberEvenOrOdd(int number) {
if (number % 2 == 0) {
return "Even number";
} else {
return null;
}
}
Mamy przechodzący test. Po sprawdzeniu czy jest coś do refaktoryzacji dodajemy teraz kolejny test który tym razem sprawdzi nam liczbę nieparzystą.
@Test
void shouldReturnOddWhenNumberIsOdd() {
//given
Math math = new Math();
//when
String result = math.checkNumberEvenOrOdd(3);
//then
assertThat(result, equalTo("Odd number"));
}
Teraz kolejnym etapem jest dodanie funkcjonalności zwrotu „Odd number” przy liczbie nieparzystej.
public String checkNumberEvenOrOdd(int number) {
if (number % 2 == 0) {
return "Even number";
} else {
return "Odd number";
}
}
Uzyskaliśmy zielony test. W fazie refaktoryzacji możemy usunąć gałąź else i zwrócić po prostu „Odd number”.
public String checkNumberEvenOrOdd(int number) {
if (number % 2 == 0) {
return "Even number";
}
return "Odd number";
}
Podsumowując na tak prostym przykładzie w skrócie została przedstawiona idea TDD. Warto pamiętać, że TDD nie jest jedyną słuszną techniką tworzenia kodu. W swoich zaletach posiada takie rzeczy jak dobry design kodu, szybkie wyłapywanie błędów, a do wad należy konieczność pisania większej ilości kodu przy testach (nie równa się to z większym czasem poświęconym na pisanie kodu programu), wymagana sumienność i dyscyplina osobista jak i całego zespołu.