Antywzorce w pisaniu testów

W kolejnych kilku wpisach przedstawię parę luźnych porad odnośnie pisania testów. Nie będzie to żaden przewodnik, ale moje własne spostrzeżenia nabyte podczas przeglądania kodu różnych projektów.

Zacznę od pewnego anty-wzorca, znalezionego na blogu http://watirmelon.com/:

s

Na rysunku widać skrajnie złą sytuację w systemie – liczbę testów w zależności od kategorii. Powinno być dokładnie odwrotnie (na górze testy jednostkowe, potem integracyjne, UI i ręczne).

Jeśli większość systemu jest przetestowana przez manualne testy to znaczy, że koszt produkcji jest bardzo wysoki, release’y długie,a błędy regresyjne stają się normą. W dobrze zaprojektowanej aplikacji, najwięcej powinno być testów jednostkowych, ponieważ są one najszybsze w uruchomieniu. Nie potrzebują żadnej zewnętrznej konfiguracji i każdy programista może je odpalić w lokalnym środowisku. Włączając do tego TDD\BDD są bardzo potężnym narzędziem i wyłapanie błędu na wczesnym etapie jest najłatwiejsze.

Oczywiście są miejsca w systemie, które nie mogą zostać pokryte testami jednostkowymi i tu w grę wchodzą testy integracyjne. Niestety bardzo często widzę błędne testy integracyjne. Powszechna zła praktyka to duplikowanie asercji logiki biznesowej w testach integracyjnych. Logikę biznesową powinniśmy przetestować w unit testach. W testach integracyjnych, jak sama nazwa wskazuję, zajmujemy się punktami integracji (np. dwóch serwisów ze sobą). Musimy się zatem upewnić, że odpowiednie interfejsy zostały wstrzyknięte i wywołane. Nie przejmujemy się z kolei, czy dany algorytm zwrócił wartość 10 czy 5. Dokładna wartość została już pokryta w unit testach.

Testy integracyjne wymagają czasami pewnej konfiguracji wstępnej, dlatego są mniej wygodne niż testy jednostkowe – stąd nie powinny stanowić trzonu naszego  QA.

Kolejna grupa to testy UI. Bardzo często  są nadużywane i używanie wyłącznie dlatego, że można je zaprezentować łatwo na sprint demo itp.  Musimy pamiętać, że wymagają one pełnego środowiska i uruchomienie ich jest najwolniejsze. W przypadku unit test, możemy skorzystać z pewnych narzędzi, które wykonują je za nas w tle – dając nam bardzo szybki feedback.  Naturalnie UI tests są automatyczne, dlatego dużo bardziej preferowane są niż testy ręczne. Nie powinniśmy jednak skupiać się na logice biznesowej, a wyłącznie weryfikować kluczowe punkty sytemu lub UI. Stanowią one pełne testy integracyjne i to jest ich ogromna zaleta.

Dodam jeszcze, że w wielu typach aplikacji, testy manualne praktycznie są nie potrzebne. Jeśli zespół potrzebuje kilka osób regularnie wykonujących ręczne testy, to zdecydowanie przedstawiony anty-wzorzec ma tam miejsce. Oczywiście są pewne specyficzne aplikacje (szczególne gry, wizualizacje itp), które wymagają stosunkowo dużej liczby testów manualnych. Natomiast w przypadku oprogramowania biznesowego (web, services) itp. nie powinno być już żadnych wymówek.

Z powyższych rozważań wynika, że testy jednostkowe powinny być najbardziej preferowane.  Ktoś może powiedzieć, że jeśli klasa A wywołuje klasę B, to bez mock’ow taki test stanowi tak naprawdę test integracyjny. O tym temacie napiszę za kilka wpisów, ale przedstawiając powyższy anty-wzorzec, mam na myśli, że testy jednostkowe to wszystkie te, które mogą być wykonane w izolacji (nie wymagają dostępu do bazy danych, web service itp.).

Warto zwrócić uwagę, że programowanie defensywne jest również bardzo skuteczne i potrafi wykryć błędy przed testami jednostkowymi. W środowisku .NET mam na myśli głównie Code Contracts. Dla chętnych polecam przejrzenie blogu ponieważ kilka razy o nich już pisałem.

Leave a Reply

Your email address will not be published.