[UT-5] Kiedy testować?

7

[ten post jest częścią mojego minicyklu o testach, pełna lista postów: tutaj]

Moment pisania testów jest nierzadko kluczowy dla zmaksymalizowania efektywności całej procedury. Po kilku chwilach zastanowienia da się wyróżnić kilka  najważniejszych etapów tworzenia oprogramowania, które z reguły są odpowiednią chwilą do implementacji testu.

TDD

Oczywisty pierwszy punkt w temacie "kiedy pisać testy?" brzmi: "przed napisaniem właściwego kodu". W praktyce, na co dzień, stosuję to dopiero od niecałego roku… i o ile wcześniej podchodziłem dość sceptycznie do tej idei, to muszę przyznać, że się całkowicie przekonałem. To jest po prostu TA droga. Mało tego – praca w ten sposób jest najzwyczajniej w świecie PRZYJEMNA.

Test Driven Development. Red -> green -> refactor. Napisz niedziałający test -> napisz najprostszy kod spełniający założenia testu -> podnieś jakość kodu bez psucia uzyskanej funkcjonalności.

Rygorystyczne i ślepe trzymanie się wytycznych TDD ma z jednej strony wiele zalet, szczególnie na etapie nauki i wdrażania się w tematykę testów. Ale z drugiej strony – czasami pisanie testów przed napisaniem właściwego kodu nie ma po prostu zbyt wiele sensu. Co prawda coraz rzadziej identyfikuję takie sytuacje, ale mimo wszystko zdarzają się.

Działanie wg zasad TDD sprawdza się znakomicie jeśli wiemy CO mamy napisać. Więc ogromna większość czasu spędzana na programowaniu wpada u mnie teraz w ramy TDD. Ale niekiedy mam tylko mętne pojęcie o tym co chcę osiągnąć, bez przemyślanej końcowej wizji i celu do którego dążę lub sposobu dotarcia do niego. Nie jest to głupie klepanie kodu byle klepać, ale raczej eksperymentowanie z różnymi podejściami w celu wybrania tego najlepszego. Specyfikowanie testów w takich okolicznościach nie jest najlepszym wyjściem, ponieważ niskopoziomowe, implementacyjne założenia zmieniają się wówczas bardzo często. Takie prototypowanie to po prostu nieśmiałe badanie możliwych dróg bez specjalnego zwracania uwagi na jakość kodu.

Ale uwaga: opisane "beztestowe sesje" to nie jest kilkutygodniowa praca nad jakimś rozwiązaniem. Trwa to zwykle maksymalnie 2-3 godziny i ma na celu postanowienie w jakim kierunku iść dalej z implementacją. Po podjęciu decyzji wracam do TDD i bogatszy o nowe doświadczenia piszę daną funkcjonalność jeszcze raz, tym razem już z zachowaniem wszystkich zasad dev-sztuki.

Bugfix

Kolejny moment, w którym staram się ZAWSZE pisać test(y), to zgłoszenie buga do systemu. Zanim zajmę się jego naprawą, muszę zdiagnozować co go powoduje. Owszem, czasem wystarczy zerknięcie w kod… ale o wiele lepiej jest napisać dla tego konkretnego scenariusza testy udowadniające, że błąd faktycznie występuje.

Daje nam to wiele korzyści. Po pierwsze – wiemy, że naprawdę coś jest źle. Po drugie – wiemy CO jest źle. Po trzecie – mamy punkt startowy do naprawiania buga. Po czwarte – mamy zabezpieczenie, że ten sam bug nie wystąpi w przyszłości (bo wtedy owe testy nam się wywrócą). Po piąte – skupiamy się na istocie problemu, dzięki czemu mamy potencjalnie spore szanse na zidentyfikowanie dodatkowych problematycznych warunków, w których z danym kawałkiem kodu coś może być nie tak. Po szóste – tworzymy archiwum i dokumentację błędu i jego rozwiązania na przyszłość.

Mógłbym pewnie ciągnąć tak dalej, ale mam nadzieję że te argumenty przekonują wszystkich do słuszności przedstawionego rozumowania.

Refactoring

Doskonałym sposobem na ostrożne wprowadzanie testów do istniejącego utrzymywanego systemu, który takowych nie posiada, jest wplatanie ich w rytuał "prac porządkowych", potocznie zwanych refaktoringiem.

W każdej aplikacji raz na jakiś czas zdarza się, że ktoś w końcu nie wytrzymuje i rozlega się krzyk "nie no k… nie dam już rady, musimy ten kawałek przepisać!!". Zwolennikom testów powinny się w tym momencie zaświecić oczka. Tak, to jest właśnie czas na zaproponowanie zespołowi/managerowi "to może zobaczymy z czym się te testy je…?". Zasada jest prosta: jak najmniej ingerując w istniejący kod staramy się, krok po kroku, dojść do miejsca, w którym posiadamy zbiór testów weryfikujących aktualną funkcjonalność. Funkcjonalność, która najprawdopodobniej jest pożądana i która już zarabia, więc nieładnie z naszej strony byłoby niechcący zmienić jej działanie. Taki proces może być dość czasochłonny, ale efekty w większości przypadków będą tego warte. Już same próby pokrycia testami jakiegoś starego molocha, betoniary pełnej spaghetti, wymuszą bardzo dokładną analizę działania utrzymywanego kodu. Mało tego, prawie na pewno nie obejdzie się bez zmian w designie tylko po to, aby testy w ogóle umożliwić. I bardzo dobrze – o to chodzi.

Po pokryciu kodu baterią testów znajdujemy się na etapie "green" z TDD. Czas na "refactor" – reorganizację, upiększanie i dodatkowe pokrywanie testami kodu tak, aby praca z nim była w przyszłości czystą przyjemnością. Dodawać chyba nie muszę, że dzięki temu w tym naszym małym wycinku olbrzymiego ohydnego systemu utworzyliśmy właśnie test-enabled-area gotowe do bezbolesnego przyjęcia nowej funkcjonalności zaimplementowanej zgodnie z zasadami TDD.

W tym miejscu podlinkuję narzędzie PEX rodem z MS. Jeśli ktoś nie zna to polecam zapoznanie się, w tym konkretnym scenariuszu może być czasami bardzo przydatne (chociaż ja osobiście nie jestem do takiego podejścia przekonany i nigdy z niego nie korzystałem).


To jak – teraz nie ma już wymówki?:) Powyższe akapity pokrywają tak szerokie spektrum programistycznych zadań, że prawie na pewno każdy z nas ma z nimi do czynienia niemal codziennie.

Na koniec jeszcze jedna odpowiedź na postawione w temacie pytanie: nieustannie i regularnie. Wtedy ma to największy sens.

Kiedy Wy piszecie testy? Może ktoś ma złe doświadczenia z TDD i zechce się podzielić?

Share.

About Author

Programista, trener, prelegent, pasjonat, blogger. Autor podcasta programistycznego: DevTalk.pl. Jeden z liderów Białostockiej Grupy .NET i współorganizator konferencji Programistok. Od 2008 Microsoft MVP w kategorii .NET. Więcej informacji znajdziesz na stronie O autorze. Napisz do mnie ze strony Kontakt. Dodatkowo: Twitter, Facebook, YouTube.

7 Comments

  1. Pozwole sobie na maly offtop: o ktorej dzis wstales zeby dodac tego posta ?

  2. tomek,
    We wszystkich "blog engines" można kolejkować posty do publikacji w przyszłości:). Niestety akurat na silniku przeze mnie wykorzystywanym nie bardzo to działa (feedburner nie łapie takich postów w RSS, nie wiem dlaczego), więc muszę dodawać ręcznie. Ale nie ma to znaczenia bo i tak wstaję 6:20-6:30.

  3. To wcześnie nawet :) Odkąd nie muszą do pracy dojeżdżać to o 7 dopiero wstaje (tak to o 5 wstawałem).
    Zgadzam się z TDD i staram stosować (choć nie wszędzie działa jak trzeba). Stosujecie też jeszcze starą dobrą metodę projektowania oprogramowania np. w UML? Czy to już przeżytek? Ja nie pamiętam kiedy ostatnio (2-3 lata temu projektowałem zanim napisałem kod) projektowałem przed napisanie kodu, ale raczej po tym jak software jest gotowe w formie dokumentacji robię UML (i tylko jak życzy sobie klient).

  4. ""beztestowe sesje" to nie jest kilkutygodniowa praca nad jakimś rozwiązaniem. Trwa to zwykle maksymalnie 2-3 godziny i ma na celu postanowienie w jakim kierunku iść dalej z implementacją. Po podjęciu decyzji wracam do TDD i bogatszy o nowe doświadczenia piszę daną funkcjonalność jeszcze raz, tym razem już z zachowaniem wszystkich zasad dev-sztuki"

    Dokladnie take samo podejscie opisywal Brett Schuchert w czasie spotkania "WORKING EFFECTIVELY WITH LEGACY CODE".

  5. w temacie testowania metod prywatnych – Uncle Bob mówi, że nie testować ich bo przetestuje je metoda publiczna (w wielkim skrócie). Więcej tutaj http://vimeo.com/20388419 (od minuty 39 – oczywiście reszta też jest bardzo ciekawa)

  6. Temat został wyczerpany. Według mnie ważne jest pisanie unit testów podczas naprawiania błędów. Naprawiamy kod, a przez napisanie testów jednostkowych zabezpieczamy się na przyszłość przed jego wystąpieniem. Być może odkryjemy pole do przepisania na nowo jakiegoś fragmentu systemu…
    Dzięki za post. Pozdrawiam.

Newsletter devstyle!
Dołącz do 2000 programistów!
  Zero spamu. Tylko ciekawe treści.
Dzięki za zaufanie!
Do przeczytania wkrótce!
Niech DEV będzie z Tobą!