5 minut(y)

Test Driven Development to metoda pracy, która bazuje głównie na unit testach. Tworzymy oprogramowanie w cyklach, przyrostowo, a każda zmiana poprzedzona jest testem.

Czym jest TDD.

Dla niektórych TDD to zasada, najpierw test (test first), dla innych wręcz wszystkie testy trzeba napisać przed implementacją. Część będzie twierdziła, że to tylko zbędne ograniczenie podczas implementacji, hamujące postęp. W pewnym stopniu zgodzę się ze wszystkimi jednak przyjrzyjmy się jej bliżej.

Test Driven Development to metodologia stawiająca unit testy na kluczowym miejscu. Traktuje je jako część implementacji, rozwiązania, które mamy zaimplementować. Zasada test first to pierwszy krok w TDD, ale to nie wszystko. W miarę rozwoju implementacji zwiększa się nam też liczba testów. Jest to pewien dodatkowy narzut i wydłuża nam czas implementacji, jednak tylko pozornie. Nie tracimy go w tak dużym stopniu przy debugowaniu i próbie przetestowania naszego rozwiązania, gdy jest już gotowe, a testów jeszcze nie ma. Podczas rozwoju naszego kodu w metodologii TDD tworzymy testowalne rozwiązanie.

Metodologia TDD jest jedną z technik programowania ekstremalnego (XP - eXtreme Programming). Jej autorem jest Kent Beck, znany i ceniony specjalista IT, choć sam siebie uważa za odtwórcę TDD :). O wszystkich technikach XP z pewnością napiszę osobny post bo warto je znać i stosować.

Cykl pracy w TDD

We wpisie o F.I.R.S.T. wspominałem o cyklu Red -> Green -> Refactor, używanym w Test Driven Development. Cykl ten to pewien rytm wyznaczający naszą pracę w tej metodologii. Zanim jednak siądziemy przed nasze IDE, zbierzmy najbardziej kluczowe wymagania i sporządzmy ich listę. Łatwiej nam będzie tworzyć kolejne przypadki testowe.

Red - każdy cykl rozpoczynamy od napisania testu. W tym miejscu będziemy formułować nowe wymaganie do naszego kodu. Piszemy jeden test, który ma sprawdzać następny krok rozwoju naszej implementacji. Nie tworzymy wszystkich testów naraz. Tylko jeden, ograniczając zakres zmian. Pierwszy test najprawdopodobniej wywoła błąd kompilacji - nasz kod jeszcze nie istnieje. To też jest wynik Red. Zaczynamy pisać testy od najprostszych przypadków, zwiększając złożoność w kolejnych krokach.

Green - kiedy test jest już gotowy i nie przechodzi, czas dopisać brakującą implementację tak, aby kod spełniał wymagania testu. Nie więcej. Ważne jest to, że potrzebujemy implementacji, która ma za zadanie sprawić, aby test przeszedł. Nie musi być to od razu gotowe rozwiązanie. Dopisz tylko tyle kodu, ile wystarczy, aby test się “zazielenił”.

Refactor - tutaj jest miejsce na poprawki i pracę z kodem. Na początku ten krok może być niezbyt pomocny. Jednak warto się choć chwilę zatrzymać i zastanowić. Refaktoring nie musi dotyczyć tylko implementacji. Jak najbardziej możemy popracować też nad testami. Tak, aby zarówno kod, jak i testy trzymały pewien poziom. Unit testy to nie dziki zachód, też powinny spełniać dobre praktyki, jak DRY czy AAA (o tym złotym standardzie napiszę z pewnością post).

Pracując w cyklach, częstu uruchamiamy testy. Mamy więc pewność, że nasz kod działa, a w przypadku pomyłki, szybko ją zlokalizujemy i naprawimy. W tradycyjnym podejściu, najtrudniej jest napisać pierwszy unit test. Sporo czasu potrzebujemy na odcięcie zależności. W TDD, pierwszy test jest prosty, mocno ograniczony. Dzięki temu łatwiej pokonać syndrom “pustej kartki” (wersja dla progamistów - “pustego ekranu” :) ).

Zalety TDD

Podczas nauki i pracy w TDD zauważyłem sporo zalet, które mogą nie być widoczne na początku, gdy jeszcze nie mamy doświadczenia w tej metodologii.

1) Praca w TDD prowadzi do generowania kodu łatwego w testowaniu. W przypadku tradycyjnego pisania implementacji. Wpierw tworzymy kod, a gdy już uznamy, że robi to, co wydaje nam się, że powinien robić, staramy się go otestować. Tracimy sporo czasu lub korzystamy ze złych praktyk, by odciąć zależności, aby móc go przetestować.

2) Koniec ze statusem naszego taska w stylu: “Mam już gotowe, tylko testy muszę dopisać”. Po czym mijają kolejne dni, a zadanie wciąż nie jest ukończone. Ta zaleta mocno łączy się z pierwszym punktem. Tutaj chcę zwrócić uwagę bardziej na nasz odbiór przez resztę zespołu, zwłaszcza kadrę zarządzającą. Gdy mówimy, że coś jest gotowe, to jest i tyle. Stajemy się bardziej wiarygodni i profesjonalni.

3) Zyskujemy zaufanie, że nasza implementacja działa. Oczywiście musimy zagwarantować, że wszystkie przypadki testowe są uwzględnione. Nie tylko tak zwany “happy path”.

4) Konkretyzujemy wymagania, zanim kod jest napisany. W tradycyjnym podejściu, gdy otrzymujemy lub wybieramy zadanie, tworzy się nam w głowie wstępny koncept, co nowa implementacja ma robić i jak ma to robić. Ten koncept może jednak być błędny, a my możemy dojść do momentu, w którym kod jest gotowy, ale nie do końca robi to, co powinien. W TDD najpierw siadamy do testu i zanim napiszemy choćby linijkę implementacji, musimy dowiedzieć się, jakie wymagania nasz kod powinien spełniać.

5) Plastyczność kodu. Dzięki temu, że nasze zmiany są już otestowane, możemy eksperymentować podczas refaktoryzacji z różnymi rozwiązaniami bez obaw, że coś zepsujemy. Odkrycie tej zalety TDD zajęło mi trochę czasu, ale było niczym przebłysk. Gdy już wszystkie testy są napisane, a pierwsza wersja rozwiązania działa i przechodzi je wszystkie, możemy próbować poprawić różne parametry naszego kodu, by zwiększyć czytelność, modularność czy zoptymalizować najważniejsze fragmenty.

6) Poczucie ciągłego postępu - zwiększona satysfakcja. Gdy kolejny test zmienia swój wynik z czerwonego na zielony, ta prosta rzecz naprawdę cieszy. Odczuwamy, że idziemy do przodu. Ta zaleta jest bardziej na podłożu psychologicznym. Niemniej, jest bardzo cenną zaletą sprawiającą, że nasza codzienna praca jest po prostu przyjemniejsza.

Wady TDD

TDD nie jest jednak lekiem na wszystko. To narzędzie, jak każde inne, ma pewien zakres zastosowań. W pewnych sytuacjach jednak nie należy go stosować.

1) W mojej ocenie TDD nie jest łatwe do nauki. Aby móc w pełni czerpać z tej metodologii, trzeba przestawić swój sposób myślenia o pisaniu kodu. TDD wymaga innego trybu pracy i na początku jest to pewnego rodzaju wysiłek intelektualny. Jeśli nie zna się w pełni tego narzędzia, można się zniechęcić do jego stosowania. Ja tak miałem. Na początku myślałem, że jest to prosta zasada test first. Nie raz porzucałem ją na wczesnym etapie nauki. Po kilku podejściach i dokształceniu się z dobrych źródeł, udało mi się opanować TDD i stałem się jego entuzjastą.

2) Cykl Red -> Green -> Refactor nie sprawdza się przy rozwiązaniach, które są zbyt małe i oczywiste. Czasem natrafiamy na takie przypadki, gdzie implementacja nasuwa się sama. Jeśli tylko dobrze znamy wymagania, po napisaniu pierwszego testu możemy od razu stworzyć pełną implementację. Następnie dopisać testy, by mieć pewność, że nie popełniliśmy błędu, i to jest w porządku! TDD ma nam pomagać w naszej pracy, a nie być świętą zasadą, której należy zawsze się trzymać.

3) Dodatkowy narzut czasowy. Gotowe rozwiązanie naszego problemu powstaje wolniej, gdyż część czasu musimy poświęcić na napisanie unit testów. Nie jest to jednak duża wada, gdyż czas ten zwraca nam się w dłuższej perspektywie. Warto jednak mieć tego świadomość. W przypadku bardzo krótkich projektów, np. hackathon, TDD może nie być dobrym wyborem.

Podsumowanie

Porównując zalety i wady TDD myślę, że można stwierdzić, że zdecydowanie więcej jest tych pierwszych. Jeśli wciąż Cię nie przekonałem. Po prostu spróbuj - jednak nie raz czy dwa. Daj tej metodologii trochę czasu, a gwarantuję, że odczujesz różnicę.

W tym wpisie chciałem przybliżyć i w prostych słowach opisać, na czym polega praca w TDD. Jestem przekonany, że opanowanie tej metodologii wzniesie każdego programistę, nie tylko C++, na wyższy poziom i jest warte wysiłku jego nauki i praktyki. Jeśli chcesz poznać bliżej TDD to polecam sięgnąć do źródła, czyli “ojca” TDD, Kenta Becka. Napisał on świetną książkę - TDD. Sztuka tworzenia dobrego kodu

Autor: Tadeusz Biela
Programista C++ | Entuzjasta TDD | Fan unit testów

LinkedIn

Zostaw komentarz