Archiwa tagu: testy jednostkowe

TestNG, Mockito i TDD – Receptury

Jakiś czas temu w zakładzie wpadła mi w ręce książka Tomka Kaczanowskiego o wielce mówiącym tytule - „Practical Unit Testing with TestNG and Mockito”.  Opisanie tak szerokiego i interesującego zagadnienia jakim jest TDD niestety troszeczkę przerasta możliwości tego bloga (no dobra, nie mam po prostu czasu i skilla by wymądrzać się w tej dziedzinie). Natomiast Tomek jako praktyk stworzył ( moim absolutnie subiektywnym i skromnym zdaniem ) wspaniałe kompendium wiedzy na temat TDD, który każdy programista powinien przeczytać.

Nie zamierzam streszczać na blogu całej książki. Mija się to absolutnie z celem, albowiem Tomek  pisze bardzo fajnie (merytorycznie i z jajem) i głupotą byłoby przepisywanie wszystkiego ‚moimi słowami’. Myślę jednak, iż dla tych, którzy chcieliby liznąć TDD w skondensowanej postaci, albo też potrzebują miejsca, do którego mogliby wrócić kiedy czegoś zapomną – poniższe recepturki będą doskonałą rzeczą. Wybór pytań i zagadnień jest też oparty na moim doświadczeniu – wannabe TDD adept i procesu dodawania testów do starego projektu. O masie rzeczy nawet nie wspomniałem, ale mam nadzieję, że to wystarczy by poczuć o co chodzi.

Oczywiście zrobię też trochę reklamy - Tomek prowadzi bloga, swoje dzieło również zaopatrzył w oddzielny blog. Tamże można dowiedzieć się jak zakupić opisywaną książkę. Gdzieś mi również mignęło, że powstaje wersja polska – poczekamy, zobaczymy.

1. To o czym w ogóle rozmawiamy?

Rozmawiamy o testach jednostkowych. Małych i autonomicznych kawałeczkach kodu, który ma na celu sprawdzać poprawność działania pisanego kodu ( dopiero powstającego przy podejściu Test Driven Development, albo też zastanego legacy code).

Testy jednostkowe nie istnieją ‚w powietrzu’ – by spełniały swoje zadanie używamy różnych bibliotek i narzędzi do ich pisania. I tutaj sedno – mowa o TestNG (do testowania) oraz frameworku mockującym (nawet nie wiem jak to przetłumaczyć - mock to imitacja działającego obiektu) - Mockito.

2. Jak to uruchomić?

TestNG  jest po prostu biblioteką, którą można swobodnie pobrać i dodać do CLASSPATH naszej aplikacji. Oczywiście dziś w dobie IDE nikt raczej nie bawi się w uruchamianie JARów w konsoli. Istnieje plugin do Eclipsa, NetBeans i IDEA Intellij. Gdzieś tam przy okazji zapodział się Maven. U mnie zależności wyglądają tak:

<dependency>
 <groupId>org.testng</groupId>
 <artifactId>testng</artifactId>
 <version>6.3.1</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.mockito</groupId>
 <artifactId>mockito-all</artifactId>
 <version>1.9.0</version>
 <scope>test</scope>
 </dependency>

3. XML? Adnotacje? Rozszerzanie klas?

Zgódźmy się, że adnotacje to fajna rzecz i na tym poprzestańmy. Poniżej przykład prostego testu, który wykorzystuje większość podstawowych adnotacji TestNG.

import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.AfterTest;

public class SimpleTestNGTest {
  @Test
  public void f() {
      System.out.println("METODA F");
  }
  @Test
  public void f2() {
      System.out.println("METODA F2");
  }
  @Test
  public void f3() {
      System.out.println("METODA F3");
  }
  @BeforeMethod
  public void beforeMethod() {
      System.out.println("BEFORE METHOD");
  }

  @AfterMethod
  public void afterMethod() {
      System.out.println("AFTER METHOD");
  }

  @BeforeClass
  public void beforeClass() {
      System.out.println("BEFORE CLASS");
  }

  @AfterClass
  public void afterClass() {
      System.out.println("AFTER CLASS");
  }

  @BeforeTest
  public void beforeTest() {
      System.out.println("BEFORE TEST");
  }

  @AfterTest
  public void afterTest() {
      System.out.println("AFTER TEST");
  }

}

Efektem uruchomienia tego testu jest:

BEFORE TEST
BEFORE CLASS
BEFORE METHOD
METODA F
AFTER METHOD
BEFORE METHOD
METODA F2
AFTER METHOD
BEFORE METHOD
METODA F3
AFTER METHOD
AFTER CLASS
AFTER TEST

Mniej więcej widać co i jak.

4. Lubiłem JUnit i mam kupę takich testów? Co z nimi zrobić?
Tomek już coś takiego przerabiał. W sensie przerobił testy z jednego na drugie. Nawet to opisał. Do tego skreślił parę słów dlaczego TestNG jest fajniejsze niż JUnit.

5. Słyszałem trendy słowo – testy parametryzowane – wot te na?

Jest to miły ficzer, który umożliwia karmienie naszych metod testowych trochę większą ilością danych niż proste wywołania dla dwóch wartości w assertEquals. Umożliwia to adnotacja DataProvider. Metody oznaczone w ten sposób muszą zwracać tablicę tablic typu Object. Kod powie pewnie więcej:

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class SimpleTestNGTest {

  @DataProvider(name="zrodloDanychNr1")
  public Object[][] dajDane() {
      return new Object[][] {
              {"key1","value1"},{"key2","value2"}
      };
  }

  @Test(dataProvider = "zrodloDanychNr1")
  public void f( String key, String value) {
      System.out.println("PARAMETRY: " + key + " - " + value );
  }

}

Efekt działania:

PARAMETRY: key1 – value1
PARAMETRY: key2 – value2

6. No dobra, ale co robi tak naprawdę to Mockito?

Dobre pytanie! Mockito służy do tworzenia imitacji działających obiektów. Kiedy powstaje kod w myśl TDD wpierw musimy stworzyć kod testów, zanim rozpoczniemy implementowanie logiki biznesowej (powiedzmy). Oczywiście by choćby próbować użycia klasy musimy ją wpierw stworzyć – inaczej kod w ogóle się nam nie skompiluje. Jednakże zamiast tworzyć od razu logikę możemy zasymulować jej działanie za pomocą składni Mockito.

Najlepiej działanie frameworka pokazać na przykładzie.


package com.wordpress.chlebik;

import static org.mockito.Mockito.when;
import static org.mockito.Mockito.verify;

import org.mockito.Mockito;
import org.testng.annotations.Test;

public class SimpleTestNGTest {

  @Test
  public void sprawdzGracza() {

      Player pl = Mockito.mock(Player.class);

      when(pl.getName()).thenReturn( "Bochenek" );
      System.out.println("GRACZ: " + pl.getName() );

      verify(pl).getName();
      verify(pl).setName("Kajzerka");
  }

  class Player {

      String name = "Chlebik";

      public String getName() {
          return name;
      }

      public void setName( String name ) {
          this.name = name;
      }
  }

}

Dzieją się tutaj 2 istotne dla nas rzeczy – możemy sprawić by dany obiekt (wywołanie metody) zachował się dokładnie tak jak chcemy (nawet kiedy w ciele metody jasno deklarujemy, że ma zwrócić obecną w obiekcie wartość), a także możemy sprawdzić czy na pewno dany obiekt został wywołany dla konkretnych metod. Wykonanie powyższego testu skutkuje takim wynikiem:

GRACZ: Bochenek
FAILED: f
Wanted but not invoked:
player.setName(„Kajzerka”);
-> at com.wordpress.chlebik.SimpleTestNGTest.f(SimpleTestNGTest.java:25)

However, there were other interactions with this mock:
-> at com.wordpress.chlebik.SimpleTestNGTest.f(SimpleTestNGTest.java:22)

Jest to świetne narzędzie do imitacji działania obiektów – chcesz by obiekt klasy HttpServletRequest zwracał spreparowaną tablicę Cookie? Nic trudnego, stwórz ją i ustaw jako zwracaną przez ten obiekt. Zauważ, że dany obiekt nawet nie musi mieć metody ustawiającej daną właściwość! Cudowna rzecz. Weryfikacja choć nie widać tego na pierwszy rzut oka jest bardzo potężnym narzędziem. Sprawdzenie czy dana metoda została (lub nie) wywołana może służyć do bardzo jednoznacznego przetestowania flow naszej aplikacji. Ciekawy przykład takowego na StackOverflow.

Powyższe to naprawdę czubek góry lodowej. Zachęcam do zapoznania się z dokumentacją Mockito.

7. Dobrze by było gdyby te testy mogły od siebie zależeć. Po co mam uruchamiać 3 inne, skoro pierwszy podstawowy nie przeszedł?

Ależ proszę bardzo. Faktycznie wykonywanie operacji np. na obiekcie zapisanym w bazie danych kiedy nie udał się test wkładający tenże obiekt do bazy mija się trochę z celem. Procesor może i się nie zmęczy, ale po co dostawać masę komunikatów o błędach. TestNG radzi sobie całkiem dobrze z takim podejściem.

package com.wordpress.chlebik;

import org.testng.annotations.Test;

public class SimpleTestNGTest {

  @Test
  public void dodajGraczaDoBazy() throws Exception {
      // testowy kod zapisu gracza do bazy
      throw new Exception("Operacja nie powiodla sie!");
  }

  @Test(dependsOnMethods = { "dodajGraczaDoBazy" })
  public void sprawdzGracza() {

      System.out.println("Sprawdzamy gracza!");

  }

}

Po uruchomieniu zobaczymy takie coś.

FAILED: dodajGraczaDoBazy
java.lang.Exception: Operacja nie powiodla sie!
at com.wordpress.chlebik.SimpleTestNGTest.dodajGraczaDoBazy(SimpleTestNGTest.java:13)
uciety stacktrace

SKIPPED: sprawdzGracza

Jak widać po niepowodzeniu pierwszego testu drugi został w całości pominięty. Funkcjonalność ta ma z całą pewnością większe zastosowanie przy przeprowadzaniu testów integracyjnych czy też funkcjonalnych.

8. Eeeej, a co z wyjątkami?

Są ;) Dają się też prosto obsługiwać. Wystarczy, że w przykładzie z poprzedniego punktu adnotacja @Test metody dodajGraczaDoBazy będzie wyglądała tak:

@Test(expectedExceptions = {Exception.class})

I obydwa testy zostaną uznane za poprawne.

9. Ok. Mamy jednakże XXI wiek i używam Springa. Da się to jakoś sklecić?

Rozumie się samo przez siebie. Od wersji 2.5 Spring do testowania używa funkcjonalności o nazwie Spring TestContext Framework. Framework ten potrafi ‚dogadać się’ z jakimkolwiek rozwiązaniem używanym do testów (JUnit, TestNG czy co kto tam sobie wymyśli). By wiedzieć co z czym polecam przeczytanie tego tutoriala o testach integracyjnych. Niestety jeśli chcemy dostać się do kontekstu Springa jesteśmy zmuszeni dziedziczyć po klasie AbstractTestNGSpringContextTests. Z drugiej jednak strony rzecz może dotyczyć tylko testów integracyjnych – jednostkowe powinny być samodzielne i autonomiczne, a wszystkie zależności możemy zmockować. O testach funkcjonalnych oraz o testowaniu samego widoku w Spring MVC na pewno jeszcze napiszę.

To tyle. Mam nadzieję, że w toku dalszych walk z TDD dorzucę jeszcze parę punktów do powyższej listy. Jeśli sami macie pomysł – piszcie na mejla lub w komentarzach.

TDD na przykładzie Grails – klasy domenowe i ich reguły

Nie tak dawno temu zawędrowałem na spotkanie WJUGa, na którym poruszono temat DDD (Domain Driven Development). Okazało się, że Grailsy są pięknym przykładem tego podejścia w praktyce. Jednakże na razie skupimy się na tym, co do tej pory omijałem w moich postach dotyczących frameworka – testach. Pisałem o nich wcześniej w kontekście JUnit, teraz zobaczmy jak zostało to zrobione w Grails.

Framework rozróżnia dwa typy testów – testy jednostkowe oraz testy integracyjne. Póki co zajmiemy się tymi pierwszymi. Zacznijmy od klas domenowych, gdyż to na ich przykładzie najlepiej pokazać jak powinien przebiegać proces budowania aplikacji w oparciu o testy. Jako podstawa posłuży nam kolejna funkcjonalność w aplikacji HowToJava – zadawanie pytań. Stworzymy zatem dwie klasy dziedzinowe – jedna będzie reprezentowała założony temat (wątek pytania, tak samo działający jak post na forum), a także konkretny wpis w ramach tego pytania/tematu.

Tworzymy zatem klasę dziedzinową HtjTopic. Wykonanie polecenia:

grails create domain-class

Powoduje utworzenie nie tylko klasy domenowej, ale także stosownych dla niej testów. Utworzona klasa testowa wygląda tak:

import grails.test.*

class HtjTopicTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
}

protected void tearDown() {
super.tearDown()
}

void testSomething() {

}
}

Mamy jak widać metodę wykonywaną na rozpoczęciu testu, a także jedną wywoływaną na koniec. Oczywiście w środku mamy też metodę będącą sednem testu. Przed jego wykonaniem zastanówmy się jednakże czego potrzebujemy w naszej klasie domenowej. Z całą pewnością takie pytanie zadane w serwisie musi mieć autora, tytuł z całą pewnością również by się przydał, data dodania myślę też by się przydała. Ostatecznie po szybkim procesie myślowym powstała taka oto lista:

  • tytuł będący łańcuchem o określonej długości
  • data utworzenia wpisu
  • autor (będzie to zalogowany użytkownik)

Dodamy też później kategorię, do której przynależy nasze pytanie, jednakże by nie komplikować kodu póki co, pozostaniemy przy naszej wersji. Generalna zasada TDD głosi, aby nie pisać nowego kodu, jeżeli testy nie kończą się sukcesem. Na razie nie mamy ani testów, ani kodu, zatem problem jest czysto akademicki. Zasadniczo jedyną rzeczą, którą można przetestować w wyraźny sposób póki co są ograniczenia i to, czy nasza klasa ich przestrzega. Stworzymy sobie obiekt imitujący zachowanie prawdziwego obiektu (tzw. mock) i na nim będziemy testować. Można by zastanowić się po co testować ograniczenia wpisywane do klasy, które mają na celu właśnie kontrolę i testowanie, czy poprawne wartości zostały wpisane? Autorzy frameworka odpowiadają na to pytanie prosto – bo tak :), ale też by uniknąć literówek, które (rzekomo) są plagą w tym przypadku. Grailsy z definicji ułatwiają życie i w związku z czym oferują gotowy szkielet do testowania. Nasza metoda testująca powinna wyglądać na razie tak:

void testConstraints() {
def existingTopic = new HtjTopic()
mockForConstraintsTests(HtjTopic, [ existingTopic ])

// Testujemy constraint notNull
def topic = new HtjTopic()
assertFalse topic.validate()
assertEquals "nullable", topic.errors["question"]

// Testujemy constraint blank
topic = new HtjTopic( question: "" )
assertFalse topic.validate()
assertEquals "blank", topic.errors["question"]

// Testujemy constraint minSize
topic = new HtjTopic( question: "test")
assertFalse topic.validate()
assertEquals "size", topic.errors["question"]

// Testujemy constraint maxSize
topic = new HtjTopic( question: "test test test")
assertFalse topic.validate()
assertEquals "size", topic.errors["question"]

// Na koniec dla pewnosci, ze poprawne dane powoduja przejscie testow
topic = new HtjTopic( question: "Jak pisać" )
assertTrue topic.validate()
}

Jej zrozumienie nie powinno nastręczać problemów. Dziwić mogą tylko dwie pierwsze linijki. Wywołanie metody mockForConstraintsTests w takim kształcie ‚uzbraja’ egzemplarze klasy domenowej w metodę validate(), co pozwala na sprawdzenie poprawności constraints (Uwaga: skróciłem długość tematu by ładniej to wyglądało w kodzie na blogu. Normalnie oczywiście powinien być dłuższy). Testy (uruchamiane w NetBeans kombinacją klawiszy Alt-F6) pokażą po pierwszym wywołaniu błędy bo i pewnie nie ma jeszcze klasy, której to obiekty chcemy utworzyć. Oto kod klasy HtjTopic:

class HtjTopic {

String question

static constraints = {
question( blank: false, size: 5..10, nullable: false )
}
}

To oczywiście na razie tyle, aby łatwiej było pokazać ideę testów. Wyniki testów możemy ładnie sobie obejrzeć w przeglądarce (katalog /tests w folderze projektu) – każdy błąd lub niepowodzenie testu zostanie odnotowane. Filozofia pisania testów jest taka, aby nie napychać jednej metody chamską wręcz ilością linii kodu. Należy to rozbić, np. ograniczając metody do konkretych pól, albo też do walidacji metodami poszczególnych ograniczneń (np. tylko wartości NULL).

Dodam jeszcze tylko, że testowanie odbywa się w spejcalnym środowisku testowym, które posiada oddzielny wpis konfiguracyjny w pliku DataSource.groovy. Oto jak powinna wyglądać konfiguracja, aby opierała się na HSQLu.

test {
dataSource {
pooled = true
driverClassName = "org.hsqldb.jdbcDriver"
username = "sa"
password = ""
dbCreate = "create-drop"
url = "jdbc:hsqldb:mem:testDb"
}
}

To tyle na dziś. W następnym wpisie zajmiemy się dodatkowymi metodami klas dziedzinowych oraz zerkniemy na inne artefakty, które można podpiąć pod testy.

TDD czyli programowanie sterowane testami

Każdy kto w programistycznych kręgach obraca się pewien czas, prędzej lub później natknął się na pojęcie Test driven development/programming. Jest to tzw. programowanie sterowane testami – metodologia (metoda?) programowania opierająca się na idei, iż przed napisaniem kodu należy utworzyć stosowne testy, które umożliwią sprawdzenie działania kodu, który dopiero zamierzamy napisać. Zatem jajko czy kura?

Po więcej szczegółów zapraszam do wikipedii. Metoda ta potrafi być naprawdę przydatna i pozwala na pisanie lepszego kodu, a także na sprawniejsze nim zarządzanie. W tym wpisie zaprezentuję wzięty z życia przykład TDD, a także mini-HOWTO szkieletu JUnit NetBeans. Zatem do dzieła.

Do napisania jest kawałek kodu, którego celem jest:

- otworzenie pliku tekstowego

- wgranie jego zawartości do zmiennej

- wyświetlenie zawartości na ekran

Rzecz prosta i zasadniczo głównie to, co może się zakończyć niepowodzeniem to pierwszy punkt, co zresztą implikuje powodzenie lub niepowodzenie działań z punktów kolejnych. Mamy taką listę rzeczy do zrobienia, zatem przed napisaniem kodu zastanówmy się co może pójść nie tak:

- plik może nie istnieć

- możemy nie mieć uprawnień do jego odczytu

- plik może okazać się po prostu pusty

- wczytanie z pliku może zakończyć się niepowodzeniem

W naszym projekcie klasy realizującej odczyt z pliku dzięki powyższej liście rysuje się wygląd poszczególnych metod, choć w zasadzie to potrzebujemy raptem jedną :)  Możnaby stworzyć kilka metod, które wykonywałyby się jedna po drugiej, uzależniając swe wykonanie od powodzenia poprzedniej. Czyli mielibyśmy jakieś fileExists(), potem pewnie isReadable(), zaś na końcu ReadFile() i być może jeszcze fileClose(). Kilka z tych metod zaimplementujemy.

Najbardziej popularnym szkieletem (frameworkiem) używanym do przeprowadzania testów jednostkowych, jest JUnit. Standardowo jest on dodawany do NetBeans, zatem stworzenie testów dla projektu tworzonego w tym IDE jest naprawdę szybkie i bezbolesne. W saym JUnit wszystkie klasy testujące inne klasy, muszą dziedziczyć po klasie TestCase z tegoż frameworka (to dla wersji 3.x). NetBeans umożliwia automatyczne wygenerowanie testów dla już istniejącej klasy w zaledwie kilka chwil. Tutaj mała uwaga. Istnieją różnice między kolejnymi wersjami JUnitNetBeans w wersji 6.1, na której pracuję dawał możliwość wyboru pomiędzy stylami 3.x i 4.x.  Różnica jest zasadniczo dość istotna – w wersji 3.x każda klasa testująca musi dziedziczyć swoją funkcjonalność po klasie TestUnit, a także trzymać się konwencji nazewniczych (dodawania suffixu -Test do nazwy każdej metody). W wersji 4.x wykorzystywany jest mechanizm asercji , więcej na temat różnic pomiędzy wersją 3.x, a 4.x można znaleźć tutaj.

Wiadomo już zatem o co mniej więcej się rozchodzi. Napiszmy zatem klasę, która zawiera interesujące nas metody:

public class ChlebikConfigChangelog {

private StringBuilder content = new StringBuilder();
private FileReader filereader;

public void loadFile(String fileName) throws FileNotFoundException
{
filereader = new FileReader(fileName);
}

public String readFile() throws IOException
{

String s;
BufferedReader br = new BufferedReader(filereader);

while((s = br.readLine()) != null)
{
System.out.println(s);
content.append(s + "\n");
}
filereader.close();

if( content.length() > 0 )
{
return content.toString();
}
else
{
throw new IOException();
}

}

}

Kod jest prosty jak konstrukcja gwoździa. Konstruktor ma za zadanie otworzyc plik poprzez stworzenie obiektu FileReader. Jeśli plik nie istnieje metoda fileExists wyrzuca wyjątek. Mamy też metodę ReadFile, która przechodzi po pliku i wczytuje do zmiennej jego treść, po czym zwraca ten łańcuch, albo też wyrzuca wyjątek jeśli okazało się, że plik był pusty. Oczywiście napisaliśmy wpierw kod, a dopiero teraz stworzymy dla niego testy. Powinno się to odbywać zasadniczo w drugą stronę, ale pragnę pokazać to na jaskrawym przykładzie. Samego pisania testów przed programowaniem trzeba się nauczyć samemu poprzez praktykę.

Testy w NetBeans tworzy się bardzo łatwo. Wystarczy kliknąć prawym przyciskiem na wybranej klasie, wybrać Tools i Create JUnit Test. Wypada zapoznać się z możliwymi opcjami generowania klasy testującej. U mnie takowa wygląda po utworzeniu następująco:

public class ChlebikConfigChangelogTest {

public ChlebikConfigChangelogTest() {
}

@BeforeClass
public static void setUpClass() throws Exception {
}

@AfterClass
public static void tearDownClass() throws Exception {
}

@Test
public void testLoadFile() throws Exception {
System.out.println("loadFile");
String fileName = "";
ChlebikConfigChangelog instance = new ChlebikConfigChangelog();
instance.loadFile(fileName);
fail("The test case is a prototype.");
}

@Test
public void testReadFile() throws Exception {
System.out.println("readFile");
ChlebikConfigChangelog instance = new ChlebikConfigChangelog();
String expResult = "";
String result = instance.readFile();
assertEquals(expResult, result);
fail("The test case is a prototype.");
}

}

I teraz do ciała każdej z metod testujących należy wrzucić kod, który przetestuje metodę. By należycie przetestować metodę readFile można zaproponować taki oto kod (modyfikując ten wygenerowany automatycznie):

@Test
public void testReadFile() throws Exception {

ChlebikConfigChangelog instance = new ChlebikConfigChangelog();

// Jesli tresc pliku to 'test'
instance.loadFile("test.txt");
String result = instance.readFile();
assertEquals("test", result);

}

@Test(expected=IOException.class)
public void testEmptyReadFile() throws IOException {

// Jesli tresc pliku nie istnieje (jest pusta)
System.out.println("readFile");
ChlebikConfigChangelog instance = new ChlebikConfigChangelog();
instance.loadFile("/test2.txt");
String result = instance.readFile();
}

Ta druga metoda służy do badania wyrzucanych wyjątków. Zastosowanie asercji @Test(excepcted=tunazwaklasywyjatku.class) buduje test (metodę), której wywołanie niezakończone wyrzuceniem wyjątku będzie uznawane za porażkę testu. Jest to bardzo użyteczny sposób na ich testowanie.

Mam nadzieję, że ten krótki przykład da podstawowe pojęcie o testach jednostkowych i TDD. Jak już wcześniej wspomniałem by w pełni wykorzystać zalety tego podejścia należy robić jedną rzecz – testować, testować, testować, a wówczas TDD stanie się naturalną drogą tworzenia oprogramowania.