Aby zacząć naukę TDD (Test-driven development) wiele nie trzeba. Wystarczy ulubione środowisko programistyczne IDE (Idea / NetBeans / Eclipse) i narzędzie do testowania (JUnit / TestNG / xUnit). I teraz albo czytamy mądre książki (polecam "TDD by Example" Kenta Becka) jednocześnie kodując, lub szukamy odpowiednich informacji w necie, albo szukamy kogoś doświadczonego, aby pokodzić w parach. No i można już uskuteczniać TDD. Tylko skąd wiadomo, że robimy to dobrze? Czy pamiętamy o wszystkich krokach? Może czasem zapominamy zrefaktoryzować kod? Czy rzeczywiście mamy rytm red, green, refactor?
W celu śledzenia i późniejszej oceny jak nam poszło TDD warto zainstalować w Eclipse’ie plugin Pulse. Kiedy pierwszy raz o nim usłyszałem (i tu podziękowania dla Bartka), pomyślałem sobie: po co komu plugin do TDD? Pewnie to jakaś ściema lub zbędny bajer. I rzeczywiście jest to bajer, ale całkiem użyteczny.
Plugin Pulse tworzy wykres naszej aktywności, zaznaczając kiedy nasze testy fail’owały, kiedy były zielone i kiedy robiliśmy refaktoring. Na stronie plugin’a można zobaczyć ciekawy filmik prezentacyjny możliwości.
W celu przetestowania plugin’u wziąłem się wiec za PrimeFactorsKata, gdyż tej Katy wcześniej nie robiłem. Efekt poniżej:
Początkowo napisałem testy dla jedynki i dwójki (pierwsze dwie czerwone kropki). Gdy napisałem test dla 4ki to się skapnąłem, że skoro jest to rozkład na czynniki pierwsze, to powinienem zwracać listę wartości, a nie pojedynczą wartość. Trzeba było wiec sygnaturę metody zmienić.
Następnie szły kolejne testy, czasem w miarę potrzeby jakiś refaktoring. Jako refaktoring jest rozpoznawane użycie któregoś z automatycznych mechanizmów, np. Extract Method (Alt + Shift + M), czy Rename (Alt + Shift + R). Niestety, jak robimy to ręcznie, to nie jest to wykrywane przez plugin. Ale w sumie niedziwne, gdyż wówczas każda edycja kodu by generowała niebieskie punkty na wykresie.
Gdy już nie chciało mi się już szukać (ani liczyć) kolejnych testowych wartości, które bym dodał do testów, przerwałem katę. Nie napisałem w pełni funkcjonalnej metody, gdyż pewnie dla jakiś kolejnych dużych wartości mogło by to nie działać. Ale nie o to chodzi w ćwiczeniach typu CodeKata by dojść do końca (bez skojarzeń;) ), a o poznanie jakiejś nowej techniki programistycznej, lub wyrobieniu sobie dobrych nawyków.
Wracając jeszcze z Warsjawy, co opisywałem we wpisie: Warsjawa 2011 już za nami, jechałem pociągiem i wziąłem się za BowlingGameKata. Tutaj już miałem sporo czasu na implementację. Nie było to moje pierwsze podejście do tego problemu, więc już jakoś w podświadomości było wiadomo, jak to rozwiązać. Ćwiczyłem dodatkowo tworzenie notatek, na temat tego, jakie testy trzeba jeszcze napisać i jakie są już napisane. Wykres z wtyczki Pulse poniżej:
Zacząłem równo o 16.00 i początkowo pisałem proste testy dla następujących przypadków (liczby to ilości kręgli zbitych w danym rzucie):
- 0 - pierwszy zielony test.
- 1- pierwszy czerwony i już po nim jakiś refaktoring.
- 1, 3 - drugi czerwony test.
- 1, 3, 4, 5 - któryś z zielonych testów po 16.10.
- Pierwszy bonus: Spare – zacząłem o 16.14 i wtedy postanowiłem zrobić większy refaktoring, tj. wprowadzić design obiektowy. Skończyłem go o 16.30 i 5 minut później już mi śmigał pierwszy test dla Spare’a. Do 16.40 jeszcze coś refaktoryzowałem, co nawed plugin zarejestrował.
- Double Spare - zacząłem chwile po 16.40 i trochę musiałem podebugować do 16.55. Ostatecznie okazało się, że w teście źle przeliczyłem oczekiwaną wartość.
- Strike – o 17.03 skończyłem implementację drugiego bonusu.
- Double Strike – skończyłem implementację o 17.33. W międzyczasie musiałem zmienić przedział w pociągu, gdyż skończył się prąd w gniazdku :P
- Spare, Strike – skończyłem o 17.39 (miałem błąd w danych testowych)
- Strike, Spare– skończyłem o 17.41(j.w.). Następnie chciałem napisać implementację Full Strike (czyli ciągle rzucamy 10 za pierwszym razem). Ale po tym jak test zfail’ował, dopisałem do mojej listy TODO jeszcze inne, prostsze testy dotyczące końcówki gry (ostatnia ramka) i zacząłem od nich implementację.
- Spare w ostatniej ramce – skończyłem o 17.54.
- Strike w ostatniej ramce – skończyłem o 18.00.
- Double Strike w przedostatniej (i ostatniej) ramce skończyłem o 18.03.
- Full Strike (ciągle rzucamy 10) – działał od razu po odkomentowaniu testu, gdyż wcześniejszymi testami zapewniłem odpowiednie działanie ostatniej ramki. Na koniec jeszcze usunąłem duplikacje z kodu ekstrachując odpowiednie metody.
Pierwszy raz doprowadziłem tą Katę do końca i jestem z niej zadowolony. Teraz moją implementację trzeba porównać z rozwiązaniem wujka Boba.
Kolejnym pluginem udostępnianym przez @iamhappyprog na stronie www.happyprog.com jest TDGotchi. Dzięki kolejnym wynikom testów zbieramy punkty i rozwiajamy nasze „zwierzątko”.
Podczas PrimeFactorsKata udało mi się uzbierać 5 punktów, przy bowlingu zapomniałem spojrzeć.
Przy zamknięciu i otwarciu widoku, punkty się resetują. możemy jeszcze obserwować nasze zwierzątko / ikonke jak się zmienia, gdy zminimalizujemy widok.
Ostatnim plugin’em tego samego autora jest PairHero. Wspiera on Pomodoro Technique i ping pong programing. Za przechodzące testy i refaktoring dostajemy punkty, a za szybkie zmiany kierownik – pilot można dodatkowo pomnożyć te punkty. Fajne jeśli akurat ćwiczmy Ping Pong'a, szybkie zmiany, lub po prostu programowanie w parach.Przykładowy screenshot poniżej.
Z przedstawionych plugin’ów najbardziej polecam pierwszy, gdyż wg. Mnie niesie największą wartość i pozwala na dobrą retrospekcje jak i porównanie wykresu z innymi developerami. Pozwala również nam zauważyć, jak często wykonujemy automatyczny refaktoring, ile czasu potrzebujemy na przejście red -> green itp.
A jak wygląda Twój puls?
Moj puls ostatnio nie bije wcale. Czekam na zmartwychwstanie. Jednak na warsztatach z chlopakami z Capa uzywalismy Pulsa kilka razy. Nie ma to ja przedstawi sprawe na obrazku, wszystko jasno widac.
OdpowiedzUsuńTDGotchi to moim zdaniem, tak jak zauważyłeś, zbędny bajer. Nawet na niego nie spojrzałeś ćwicząc katę:)
OdpowiedzUsuńPairHero może się przydać na wszelkich warsztatach typu CodeRetreat jako pomoc w pilnowaniu kroku "switch". Na koniec każdego "pomidora" serwowane są statystyki: liczba zielonych testów, refactoringów. Brakuje jedynie liczby switch'ów. W wolnej chwili można dopisać :)
Obszerna analiza BowlingGameKata - jak mają się prowadzone przez Ciebie notatki do błędnych danych testowych?
PS. "Extract Method"
@Bartek Co rozumiesz przez błędne dane testowe? W TDD nie chodzi o "sito" testowe, czyli atakowanie naszych metod błędnymi danymi testowymi, o ile nie jest to uwzględnione w wymaganiach. W opisie BowlingGameKata nie ma wzmianki o tym jak ma się zachowywać nasz kod w przypadku błędnych danych jak wartości ujemne, lub liczba zbitych kręgli większa niż 10. Stosując TDD powinniśmy tylko pisać to co zostało zdefiniowane w wymaganiach.
OdpowiedzUsuńJeżeli później nasz kod wystawiamy na zewnątrz, to oczywiście tak - trzeba go zabezpieczyć przed błędnymi danymi testowymi.
W przeciwnym wypadku i jeśli mamy zaufanie do naszego teamu, to często możemy pominąć sprawdzanie błędnych wartości, ufając, że nikt nie użyje naszej klasy w nieodpowiedni sposób. Kwestia trochę dyskusyjna, wszystko zależy od konkretnego projektu.
Podsumowując, pisanie przypadków testowych z błędnymi danymi to programowanie defensywne i wykracza po za "odkrywanie interfejsu" za pomocą TDD. Czasem jednak należy je stosować jako kolejny etap wytwarzania kodu.
Cześć w zdaniu :
OdpowiedzUsuń"Podczas PrimeFactorsKata udało mi się uzbierać 5 punktów, przy bowlingu zapomniałem sporzeć."
masz literówkę. Podejrzewam, że chodziło o wyraz spojrzeć.
@Hopbit Thx za uwagę, już poprawione.
OdpowiedzUsuń