Testy jednostkowe (inaczej Unit testy) definiuje się jako rodzaj testowania oprogramowania, w którym testowane są poszczególne jednostki/elementy oprogramowania.
Testowanie jednostkowe aplikacji odbywa się podczas jej tworzenia (kodowania). Celem testów jednostkowych jest izolacja części kodu i sprawdzenie jego poprawności. Testy jednostkowe zazwyczaj są wykonywane przez programistów (ale nie zawsze).
W SDLC, STLC czy modelu V, testowanie jednostkowe jest pierwszym poziomem testowania przeprowadzanym przed testowaniem integracyjnym. Testowanie jednostkowe jest techniką testowania Whitebox, wykonywaną jak wspominałem zwykle przez programistów. Chociaż w praktycznym świecie z powodu kryzysu czasowego lub niechęci programistów do przeprowadzania testów, specjaliści QA również wykonują takie testy.
Po co nam testy jednostkowe?
Czasami programiści próbują zaosczzędzić czas wykonując tylko minimalne testy jednostkowe. Jest to mit, ponieważ pominięcie testów jednostkowych, czy też niedokładne sprawdzenie prowadzi do dużo wyższych kosztów późniejszej naprawy podczas testów systemu, czy testów integracyjnych. Prawidłowe testy jednostkowe wykonane podczas fazy rozwojowej oszczędzają nie tylko czas, ale i pieniądze. I to jest główny powód, aby przeprowadzać testy jednostkowe.
A zatem: jak wspomnieliśmy, testy jednostkowe naprawiają błędy na wczesnym etapie cyklu rozwojowego i pozwalają zaoszczędzić i czas i pieniądze. Pomagają zrozumieć programistom, gdzie jest jakiś problem w kodzie, dzięki czemu mogą szybko zareagować i wprowadzić zmiany. Dobre testy jednostkowe mogą służyć jako dokumentacja projektowa (wspominałem o tym w poprzednim Podcaście, kiedy mówiłem o różnicach, wadach i zalteach testów manualnych jak i automatycznych – zachęcam do odsłuchania). Następnie, testy jednostkowe pomagają w ponownym wykorzystaniu kodu – można migrować swój kod i swoje testy do nowych projektów i dopasować je do ponownego uruchomienia.
Jak przeprowadzać testy jednostkowe?
Tutaj nie zaskoczę Was, ponieważ są dwie drogi:
- testowanie manualne,
- testowanie automatyczne.
Testy jednostkowe zą zwykle zautomatyzowane, ale nadal mogą być wykonywane również manualnie. Preferowanym jednak sposobem jest automatyzacja. Manualne podejście do testowania jednostkowego może opierać się na dokumencie zawierającym instrukcje krok po kroku.
Podejście automatyczne,
Programista zapisuje jakiś fragment kodu w aplikacji tylko po to, aby przetestować działanie konkretnej funkcji. Następnie komentują ten fragment i w końcu usuwają kod testowy po uruchomieniu i przetestowaniu. Deweloper może też wyodrębnić daną funkcjonalność, aby przetestować ją bardziej szczegółowo. Jest to dokładniejsza metoda testów jednostkowych, która polega na kopiowaniu i wklejaniu kodu do własnego środowiska testowego niż do jego naturalnego środowiska. Izolowanie kodu pomaga w ujawnieniu niepotrzebnych zależności pomiędzy testowanym kodem a innymi jednostkami lub danymi w produkcie. Zależności te można następnie wyeliminować. Programista zazwyczaj wykorzystuje UnitTest Framework do opracowania zautomatyzowanych przypadków testowych. Korzystając z frameworka automatyzacji, deweloper wprowadza kryteria do testu w celu weryfikacji poprawności kodu. W trakcie wykonywania testów, framework rejestruje niepowodzenie testów. Wiele frameworków również automatycznie oznacza i raportuje wyniki przeprowadzanych testów. W zależności od stopnia zaawansowania błędu, framework może zatrzymać dalsze testy.
Technki pokrywania kodu stosowane w testach jednostkowych to:
- Poświadczenie pokrycia (Statement Coverage)
- Decyzja (Decision Coverage)
- Zakres (Branch Coverage)
- Warunki (Condtion Coverage)
Przykładem testów jednostkowych może być np. Obiekty Mock.
Testy jednostkowe polegają na tworzeniu obiektów typu mock do testowania sekcji kodu, które nie są jeszcze częścią kompletnej aplikacji. Obiekty takie wypełniają brakujące części programu. Na przykład, możesz mieć funkcję, która potrzebuje zmiennych lub obiektów, które nie zostały jeszcze utworzone. W testach jednostkowych, będą one uwzględnione w postaci obiektów typu mock utworzonych wyłącznie w celu przeprowadzenia testów jednostkowych na tej części kodu.
Jakich narzędzi używamy do testów jednostkowych? Otóż dostępnych jest kilka zautomatyzowanych narzędzi wspomagających przeprowadzanie testów jednostkowych, i tak, są nimi:
JUnit (chyba najbardziej popularny): jest darmowym narzędziem do testowania używanym w języku programowania Java. Dostarcza on informacji pozwalających zidentyfikować metodę testową. To narzędzie testuje najpierw dane, a następnie wstawia je do kodu.
NUnit: jest szeroko stosowaną jednostkową strukturą testującą dla wszystkich języków .net. Jest to narzędzie open source, które pozwala na ręczne pisanie skryptów. Obsługuje testy oparte na danych, które mogą być przeprowadzane równolegle.
JMockit: jest narzędziem do testowania jednostek open source. Jest to narzędzie pokrycia kodu z metryką linii i ścieżki. Pozwala ono na manipulowanie API z zapisem i weryfikacją składni. Narzędzie to oferuje pokrycie linii, pokrycie ścieżki i pokrycie danych.
EMMA: jest zestawem narzędzi open-source do analizy i raportowania kodu napisanego w języku Java. Emma wspiera takie typy pokrycia jak metoda, linia, blok podstawowy. Jest on oparty na języku Java, więc nie jest zależny od zewnętrznych bibliotek i może uzyskać dostęp do kodu źródłowego.
PHPUnit: jest jednostkowym narzędziem testującym dla programisty PHP. Wymaga niewielkich części kodu, który jest nazywany jednostką i testuje każdą z nich oddzielnie. Narzędzie to pozwala również programistom na używanie metod asertywnych w celu zapewnienia, że system zachowuje się w określony sposób.
To oczywiście tylko niektóre z dostępnych narzędzi do testowania jednostkowego. Jest ich o wiele więcej, szczególnie dla języków C i Java, ale na pewno można znaleźć narzędzie do testowania jednostkowego dla naszych potrzeb, niezależnie od używanego języka.
Powszechnym mitem dotyczącym testów jednostkowych jest stwierdzenie, że takie testy wymagają sporo czasu, a przecież programiści zawsze wszystko muszą zrobić „na wczoraj” i tego czasu nie mają. Poza tym przecież ich kod jest solidny, stabilny i wolny od błędów. Nie potrzebują więc go sprawdzać i testować.
Mity z samej definicji są czymś fałszywym, fałszywymi założeniami. Założenia te prowadzą do błędnego koła:
Więcej presji = mniej testów
Mniej testów = mniej stabilny kod
Mniej stabilny kod = mniejsza produktywność i dokładność
Mniejsza produktywność i dokładność = Większa presja
I koło się zamyka.
Prawdą natomiast jest, że testy jednostkowe zwiększają szybkość rozwoju aplikacji.
Często Programiści myślą, że Testowanie Integracyjne wychwyci wszystkie błędy i z tego powodu nie wykonają testów jednostkowych.
Kiedy poszczególne komponenty są już zintegrowane, bardzo proste błędy, które można było bardzo łatwo odnaleźć i naprawić w testowanych komponentach/modułach, wymagają bardzo długiego czasu na prześledzenie i naprawę.
Przyjrzyjmy się zatem zaletom testów jednostkowych:
- Deweloperzy chcący dowiedzieć się, jaką funkcjonalność daje dany moduł i jak z niej korzystać, mogą przyjrzeć się takim testom jednostkowym, aby uzyskać podstawowe zrozumienie API tego modułu.
- Testy jednostkowe pozwalają programiście na późniejszą zmianę kodu źródłowego i upewnienie się, że moduł nadal działa poprawnie (np. podczas testów regresji). Procedura polega na zapisywaniu przypadków testowych dla wszystkich funkcji i metod, tak aby w przypadku, gdy jakaś zmiana spowoduje błąd, można było ją szybko zidentyfikować i naprawić.
- Ze względu na modułowy charakter testowania jednostkowego, możemy testować części projektu nie czekając na ukończenie innych.
Wady testów jednostkowych:
- nie możemy oczekiwać, że testy jednostkowe wykryją każdy błąd w programie, ponieważ nie jest możliwa weryfikacja wszystkich ścieżek wykonania nawet w najbardziej banalnych systemach.
- testy jednostkowe ze swej natury koncentrują się na jednostce kodu. W związku z tym nie mogą wychwycić błędów integracji lub błędów szerokiego poziomu systemu.
A zatem, zalecane jest stosowanie testów jednostkowych w połączeniu z innymi czynnościami testowymi.
Na koniec jeszcze przyjrzyjmy się dobrym praktykom w testach jednostkowych
- Przypadki testowe powinny być niezależne. W przypadku jakichkolwiek ulepszeń lub zmian w wymaganiach, przypadki testów jednostkowych nie powinny być naruszone.
- Testowanie tylko jednego kodu na raz.
- Postępowanie zgodnie z jasnymi i spójnymi zasadami nazewnictwa w testach jednostkowych.
- W przypadku zmiany kodu w dowolnym module, należy upewnić się, że istnieje odpowiedni przypaek testowy dotyczący tego modułu, a sam moduł przechodzi testy przed zmianą.
- Błędy wykryte podczas testów jednostkowych muszą zostać naprawione przed przejściem do kolejnej fazy cyklu rozwoju oprogramowania.
- Przyjęcie podejścia “testuj jako swój kod”. Im więcej kodu napiszesz bez testowania go, tym więcej ścieżek musisz sprawdzić pod kątem błędów.
Jak widzisz, testowanie jednostkowe może być bardzo angażujące. Może być zarówno skomplikowane, ale też i proste, w zależności od testowanej aplikacji i stosowanych strategii, narzędzi, podejścia. Testy jednostkowe są zawsze konieczne na pewnym etapie. To nie podlega dyskusji.
I to tyle w dzisiejszym odcinku. Dziękuję Ci za Twój czas i wysłuchanie.
Życzę Ci udanego dnia i wielu sukcesów.
Do usłyszenia w kolejnym odcinku!