Może rzucę coś od siebie, z właśnego nie-tak-duźego doświadczenia…
TDD to przede wszystkim zmiana w myśleniu. Najtrudniejsze w całym tym procesie jest zrozumienie samej idei - a zatem przejścia od klupania kodu do projektowania go w trakcie pisania testów.
Weźmy se prostą klasę reprezentującą Test (https://github.com/Auditr/Test/). Na początek proste założenia:
- Klasa ta ma reprezentować zbiór czynności, które są wykonywane na zadanej stronie WWW
- Strona ma być oceniona pod względem tego czy czynności te udało się wykonać poprawnie
- User ma dostać wynik punktowy
Założenia proste, ale już nam uzmysławiają mniej więcej jak musimy to pisać w taki sposób, żeby kod był jak najlepiej pokryty testami. Sam wygląd API również będziemy ustalać pisząc testy (implementacja jest tylko wypełnieniem założeń narzuconych przez testy!):
- Całość systemu podzielimy na 3 części: klasę reprezentującą stronę, klasę reprezentującą sam test i klasę reprezentującą wynik. Dzięki takiemu podziałowi każdy element będzie można przetestować oddzielnie, bez zastanawiania się czy przypadkiem zależności pomiędzy nimi (lub - w przypadku strony - połączenie sieciowe) nie wpłynęły na wynik. Stronę będziemy zatem mockować, żeby zachowywała się w ściśle określony sposób i tym samym test produkował przewidywalne wyniki
- Zastanawiamy się jakie metody będą nam potrzebne i co powinny zwracać. Jak już to wymyślimy, piszemy prosty test sprawdzający daną rzecz, np. wiadomo, że test musi się wykonać (Test::run()) zanim będzie możliwość pobrania wyniku (Test::getResult()). Tym samym należy sprawdzić czy rzeczywiście tak jest (czyli inaczej mówiąc: czy klasa Test rzuci wyjątek jeśli najpierw wywołamy Test::getResult() a dopiero potem Test::run()). W podobny sposób możemy potestować pozostałe części naszego kodu
- Kiedy już napiszemy sobie ładny projekt naszego API w postaci testów, warto sprawdzić czy nasz kod je oblewa (hint: nasz kod nie istnieje, więc oblewa ;)). Jeśli oblewanie działa, czas zacząć pisać kod tak, żeby te testy zdawał (czyli wyposażmy naszą metodę Test::getResult() w warunek, który sprawdzi czy wcześniej zostało odpalone Test::run() i w razie potrzeby walnie wyjątkiem)
- Trzeba będzie kiedyś dodać nową funkcjonalność? Żaden problem - dodamy ją w testach, a później dopiszemy kod pod to ;)
Przykładowe test do klasy Test można znaleźć tutaj: https://github.com/Auditr/Test/blob/master/tests/TestTest.php → nie twierdzę, że są one idealne, ale zapewniają, że kod działa tak, jak powinien.