Scroll to top
en pl

Testy jednostkowe – dlaczego warto


Mateusz Olczak - 26 września 2019 - 0 comments

Przyczyna i skutek

W 2004 roku J. Mackye Gruber i Eric Bress wyreżyserowali film z Ashtonem Kutcherem w roli głównej. Mowa oczywiście o filmie “Efekt motyla”. Główny bohater cierpiący na zaniki pamięci odkrywa, że może cofać się w czasie i zmieniać swoje wybory. Przekonuje się również, że nawet pozornie nieistotne działanie może nieść ze sobą ogromne konsekwencje. 

Z taką samą sytuacją spotykają się w swojej codziennej pracy programiści. Wprowadzając jakiekolwiek zmiany, trzeba mieć świadomość, że mogą one wpływać na istniejący kod. Niemal każda nowa funkcjonalność wymaga dokonania zmian w istniejącym kodzie. Często  pozornie nieistotne modyfikacje, dokonywane w jednym module, są przyczyną zmian w innych modułach. Powoduje to pojawienie się nieoczekiwanych błędów, które często nie są wykrywane nawet w ramach testów regresyjnych. Przyczyna takiego stanu jest prosta – nikt nie spodziewał się, że należy przetestować regresyjnie dany moduł, który pozornie nie jest powiązany w żaden sposób z wprowadzoną zmianą.

Merge to słowo, które wywołuje stres u większości programistów. Wszystko przez to, że podczas merge’y dosyć często zdarzają się konflikty. Dodatkowo, jeśli zmiany są bardzo duże i z jakiegoś powodu nie ma możliwości skorzystania z opinii stron, które commitowały zmiany, programista odpowiedzialny za merge’owanie zmian zostaje zupełnie sam z koniecznością rozwiązania konfliktów. W takich przypadkach, nie mając pełnej znajomości tych rozwiązań, nowe funkcje mogą zostać błędnie zmerge’owane. Oczywiście takie błędy mogą się zdarzyć nawet wtedy, gdy znamy kod i mamy do dyspozycji commiterów – niestety zazwyczaj tego typu błędy kończą się mniejszą lub większą katastrofą.

Unikanie komplikacji po merge’ach

Odpowiedzią na te problemy jest pisanie testów. Błędy mogą zdarzyć się każdemu programiście, na każdym etapie tworzenia oprogramowania. Najważniejsze, aby wykryć je odpowiednio wcześnie – najlepiej zanim produkt trafi do klienta. Właściwie napisane testy sprawdzają jak poszczególne fragmenty kodu zachowają się w niestandardowych warunkach lub specyficznych sytuacjach. Pisanie testów może zapobiec pojawianiu się błędów po zmerge’owaniu kodu, wprowadzeniu błędów do istniejących modułów/fragmentów kodu, a także innym potencjalnym katastrofom – ale to nie wszystkie zalety testowania kodu.

Ochrona przed błędami

Głównym zadaniem testów jednostkowych jest wykrywanie i eliminacja błędów. Błędy mogą powstawać z wielu różnych przyczyn. Testy chronią program przed błędami w logice biznesowej, a także przed błędami, które są wynikiem wprowadzenia przypadkowych zmian w kodzie i nie są wychwytywane przez IDE ani w trakcie code review.

Testy wykorzystywane są także do szybkiego sprawdzenia jakości i poprawności nowej wersji. Przed wysłaniem kodu do repozytorium, można przekazać paczkę do testów jednostkowych, co pozwoli na uniknięcie potencjalnej katastrofy.

Merge pod kontrolą

Podczas merge’owania zmian często pojawiają się konflikty, a ich rozwiązanie nie zawsze jest proste, dlatego kluczowe jest sprawdzenie poprawności merge’a. Kontrola po łączeniu zmian oraz wskazanie problemów w integracji nowych funkcji powinno być zapewnione przez testy jednostkowe. Dzięki temu można wykryć potencjalne błędy jeszcze przed testami integracyjnymi, które trwają znacznie dłużej niż testy jednostkowe, czy testami manualnymi E2E.

Poznawanie funkcjonalności

Gdy programista trafia do nowego zespołu, jego nadrzędnym celem jest szybkie wdrożenie się w projekt. Aby swobodnie poruszać się po projekcie, programista musi poznać nie tylko jego funkcjonalność – musi także zapoznać się z technologiami, jakie stosowane są w tworzonym oprogramowaniu. Również w tym przypadku pomocne są testy. Nowi programiści mają możliwość szybkiego zapoznania się z funkcjami systemu poprzez prześledzenie testów jednostkowych, ponieważ można z nich odczytać m.in. niuanse algorytmów występujących w funkcjach.

Testy przydają się także podczas dodawania do projektu nowych bibliotek. Początkowo, przy próbie skorzystania z nowej biblioteki, programista może mieć problemy z właściwym zrozumieniem jej działania lub poprawnym użyciem API. Testy jednostkowe pozwalają szybko sprawdzić działanie bibliotek, a tym samym ułatwiają zastosowanie tych bibliotek w praktyce.

Zaufanie do aplikacji

Wgranie niesprawdzonego kodu do repozytorium może mieć naprawdę fatalne konsekwencje – od produkcyjnego crashu, aż do nagromadzenia nieobsłużonych błędów i utrudnieniu pracy kolegom z zespołu. Zastosowanie testów buduje zaufanie do aplikacji – przetestowane i sprawdzone w wielu różnych warunkach funkcje z o wiele większym prawdopodobieństwem będą działać po przekazaniu ich w ręce użytkowników. 

Oczywiście należy pamiętać, że zaufanie do przetestowanej aplikacji nigdy nie powinno być bezgraniczne. 

Bezpieczny refactor

Nowe wersje języka programowania, zmiany w dotychczasowych funkcjonalnościach lub chęć dodawania nowych komponentów – to wszystko sprawia, że kod czasami wymaga przebudowy. Refactoring kodu niesie ze sobą jednak pewne zagrożenia. Zmiany w kodzie mogą doprowadzić do powstania błędów, zaburzenia logiki lub utraty kompatybilności poszczególnych fragmentów kodu.

Dzięki testom można bezpiecznie wykonywać refactor, bez obaw, że podczas przebudowy kodu zostanie zaburzona logika biznesowa. Pozwala to również zaoszczędzić czas, ponieważ testy regresyjne nie muszą być wykonane w tak szerokim zakresie, jak miałoby to miejsce bez odpowiedniego pokrycia testami jednostkowymi. Testy zabezpieczają proces refactoringu kodu poprzez zapewnienie stałej kontroli nad rozwojem aplikacji i ciągłe monitorowanie jej działania. Ułatwiają także rozwiązywanie problemów i konfliktów.

Załóżmy, że kilku programistów pracuje jednocześnie nad kilkoma funkcjami systemu. Odpowiednia konfiguracja systemu CI (budowanie każdego feature brancha) pozwala na sprawdzenie czy dany feature nadaje się wstępnie do zmerge’owania. Taka klasyfikacja jest możliwa poprzez określenie poprawności wykonania testów jednostkowych na danym branchu.

Kontrola własnego kodu

Podczas pisania kodu, niektóre błędy logiczne nie są widoczne na pierwszy rzut oka. Pisanie testów wiąże się z ponowną weryfikacją poszczególnych fragmentów programu. Dzięki testowaniu ujawniają się błędy w logice kodu, a programista może na bieżąco je naprawiać.

Eliminacja czynnika ludzkiego

Nie od dziś wiadomo, że mylić się jest rzeczą ludzką. Maszynom zazwyczaj pomyłki się nie zdarzają, dlatego właśnie automatyzacja procesów jest dynamicznie rozwijającym się obszarem branży IT. Automatyzacja testów jest jednym z rozwiązań, które sprawiają, że kolejne procesy stają się niezależne od człowieka. Eliminacja przypadkowych błędów zdecydowanie ułatwia pracę programistów. Pominięcie roli człowieka w procesie testowania zwiększa pewność, że testy przeprowadzone są prawidłowo za każdym razem. To także ogromna oszczędność czasu – zamiast poświęcać go na manualne wyszukiwanie błędów, programista może skoncentrować się na tworzeniu nowego kodu.

Pisz testy – warto!

Dobrze napisane testy to naprawdę duże ułatwienie, tym bardziej, że pisanie testów jest obecnie jednym z kryteriów akceptacji zadań. Testy szybko dostarczają informację o błędach, minimalizują ryzyko ich wystąpienia i zabezpieczają przed regresją. Właściwie dobrane testy wpisują się w prawidłową architekturę programu i proces wytwarzania oprogramowania, a także optymalizują pracę nad wprowadzaniem nowych funkcjonalności.

Related posts