blog.testowka.pl

Archiwum wiadomości z Czerwiec, 2012

Dlaczego automatyzujemy testy?

opublikowany przez 21, Cze, 2012, w kategoriach Agile, Automatyzacja, CI, Programowanie, Testowanie, XP

Mamy różne rodzaje testów. Jeśli chodzi o testerów to najczęściej zajmują się oni automatyzacją testów funkcjonalnych GUI czy też testami typu end-to-end.

Warto się zastanowić po co tworzymy takie testy automatyczne? Jeśli robimy to wyłącznie by przyspieszyć testowanie, to nie jest to najlepsza odpowiedź. Celem tworzenia takich testów powinno być poprawianie jakości – może nie bezpośrednio ale ogólnie testy automatyczne powinny przyczyniać się do poprawy jakości. Robię to poprzez dostarczanie szybkiej – dużo szybszej niż tester manualny informacji zwrotnej na temat działania produktu, a przede wszystkim na temat tego czy programista wprowadzając zmiany niczego nie zepsuł. Jest to niezwykle istotne zwłaszcza, gdy mamy do czynienia z systemami typu legacy – kaszana bez wyraźnej, przejrzystej architektury i testów jednostkowych. Systemy tego typu maja to do siebie że bardo trudne, o ile wręcz niemożliwe jest przetestowanie ich przy użyciu testów jednostkowych. Tworzenie unit testów do już istniejącego kodu, napisanego przed testami jest bardzo czasochłonne (swoją drogą to jeden z powodów dla którego niektórzy mówią, że pisanie testów jest strasznie kosztowne i czasochłonne). Kod który nigdy nie był pisany z myślą o testach jednostkowych, które będą go testowały często jest po prostu nietestowalny.

By móc poprawiać jakość naszego produktu musimy być w stanie poprawiać kod i jego jakość. Niestety bez szybkiej informacji na temat tego czy kod działa  – na przykład w postaci unit testów nie mamy nigdy pewności czy nasze zmiany niczego nie popsują, a co za tym idzie brakuje nam  odwagi by cokolwiek zmieniać i poprawiać. Pętla się zamyka – nie możemy zmienić nie testowalnego kodu tak by był testowalny bez obawy o to, ze czegoś nie popsujemy. Błędne koło się zamyka a dług technologiczny ciągle rośnie.

Jednym ze sposobów jest wdrożenie testów typu end-to-end które traktują testowany system jak „black box” lub „gray box”, do którego mają dostęp tylko w odpowiednich miejscach. Takie testy mają niestety kilka wad – na przykład są wolne i trudne w utrzymaniu.

Powyższe problemy to jeden z wielu powodów stosowania w projektach tzw. piramidy testów, która zakłada, że będziemy tworzyć jak najwięcej testów jednostkowych, trochę mniej testów funkcjonalnych i akceptacyjnych, a testów typu end-to-end nie będziemy tworzyć wcale, lub będą to tylko skrajne przypadki.

Takie podejście sprawdza się idealnie, rozpoczynamy projekt od zera i od samego początku postępujemy według wyżej wymienionych zasad. Niestety rzeczywistość jest inna. Na początku projektów informatycznych mało kto przejmuje się automatyzacja w ogóle, o testach jednostkowych i TDD już nawet nie wspomnę. Testy automatyczne wdraża się przeważnie dopiero, gdy zaczyna się już robić na prawdę niedobrze, a dług technologiczny daje o sobie znać na każdym kroku. W ten sposób powstają właśnie systemy typu legacy.

Gdy kilka miesięcy temu na konferencji 33rd degree podczas jednej z prezentacji Uncle Bob powiedział coś w stylu: „Nie piszcie testów end-to-end – one są złe”, a ja zobaczyłem bezmyślnie przytakujące głowy setek programistów siedzących na sali pomyślałem sobie: „Cholera – ostatnie 2 lata prowadzonej przez nas indoktrynacji w dziedzinie automatyzacji testów w naszym kraju właśnie trafił szlag…”. Miałem o to spory żal do Bob’a, który zresztą na niego wylałem w postaci bardzo długiej dyskusji na temat legacy code etc. Bob oczywiście na myśli miał projekty typu green-field, gdzie zaczynamy od zera. Oczywiście bardzo dobrze, że skorzystał ze swojego autorytetu i może przynajmniej kilka osób do tego przekonał, dzięki czemu w przyszłości będzie znacznie mniej systemów przepełnionych legacy code. Ale co z projektami, które już istnieją i które nadal trzeba rozwijać? To właśnie w takich projektach pracuje większość testerów (domyślcie się dlaczego).

Łatwo znaleźć rozwiązanie dla systemów już istniejących, gdy uświadomimy sobie, że celem testowania nie jest tylko testowanie samo w sobie ale też poprawa jakości. Podstawowym celem wdrożenia testów automatycznych jest zapewnienie możliwości wprowadzania bezpiecznych zmian – podobnie jak celem testów regresyjnych (które przypadkiem powstają przy wdrożeniu automatyzacji) jest dostarczenie informacji zwrotnej na temat tego, czy nasze zmiany nie wprowadziły błędów w istniejącej już funkcjonalności. Aby móc cokolwiek zmieniać tworzymy takie testy które dadzą nam przynajmniej ogólna informację na temat tego czy funkcjonalność która zmieniamy nie uległa popsuciu z punktu widzenia użytkownika.

W skrócie tworzymy odwróconą piramidę testów – z dużą ilością testów end-to-end i funkcjonalnych. Dzięki temu możemy zmieniać kod aplikacji i poprawiać jego jakość (refaktoryzować, zmieniać architekturę etc.) sprawiając, że staje się on testowalny także na niższych poziomach. Za każdą zmianą idzie dopisywanie nowych testów jednostkowych (a nawet to zmiany sterowane są pisaniem testów jednostkowych jak w TDD). Po pewnym, czasie mamy testowalny system z przejrzystą architekturą, w której każdą warstwę możemy przetestować oddzielnie, a GUI i logika w nim ograniczone są do minimum. To jest dobry moment by zacząć pozbywać się naszych testów typu end-to-end. Tak! Właśnie tak! Cały czas tworzyliśmy testy typu end-to-end z myślą o tym, że za chwilę je usuniemy. Największym kosztem podczas utrzymywania testów są duplikacje – więc jeśli tworzymy testy jednostkowe, które w przybliżeniu testują to samo co nasze testy end-to-end to oczywistym staje się potrzeba usunięcia tych, które są bardziej kosztowne i mniej wartościowe – end-to-end. W ten sposób stopniowo obracamy naszą piramidę testów i zaczyna ona powoli wyglądać tak jak powinna.

Celem całej naszej pracy nie jest zwiększenie pokrycia testami – co w podanym przykładzie mogło by doprowadzić do pokrycia nawet powyżej 100% (oczywiście zależy jak liczonego) – pytanie czy taka metryka cokolwiek nam mówi poza tym, że straciliśmy dużo czasu? Prawdziwym celem jest poprawa jakości, jakości na najniższym poziomie, zapewnienie poczucia bezpieczeństwa podczas wprowadzania zmian, wydzielenie odpowiednich modułów i domen w naszej aplikacji, odseparowanie modelu o danych, logiki od interfejsu użytkownika, itd.

Powyżej opisałem jeden (jak dotąd z pośród sprawdzonych przeze mnie w praktyce, jedyny działający) z kilku sposobów radzenia sobie z długiem technologicznym.

4 komentarze więcej...