W tym artykule opiszę dlaczego testowanie kodu aplikacji jest tak ważne, opiszę jak tworzyć różne rodzaje testów oraz pokażę przykład JUnit test dla Javy. Zawsze powtarzam, jeżeli chcesz spać spokojnie, to pisz testy kodu aplikacji. Pod pojęciem testy rozumiem różne rodzaje testów np.: testy jednostkowe, testy integracyjne, testy automatyczne oraz manualne. Można wryóżnić kilka technik pisania testów.
Wstęp
Ludzie dzielą się na tych, którzy piszą testy oraz tych, którzy będą je pisali. Wszyscy wiemy jak wyglądały testy aplikacji na produkcji robione przez mBank – niebezpiecznik.pl (5/8/2020) – tak nie robimy, chcemy tego uniknąć.
Techniki pisania testów
Na wstępie wspomniałem różne rodzaje testów, omówię je szerzej później. Do rodzajów testów można dodać jeszcze różne techniki pisania testów.
TDD – Test Driven Development
Najpopularniejszą techniką pisania testów jest Test Driven Developmnet – TDD. Technika TDD zakłada w pierwszej kolejności pisanie testów, a następnie pisanie właściwej klasy, którą testujemy. Dzięki temu wymuszamy pisanie testów do tworzonego kodu. TDD wyrabia dobry nawyk dzięki, któremu nasz kod źródłowy “od razu” posiada testy. Polecam książkę TDD. Sztuka tworzenia dobrego kodu.
“Technika” dopisywania testów
Kolejną “techniką” pisania testów jest dodawanie testów do już istniejącego kodu źródłowego w trakcie refaktoryzacji lub z powodu braku testów. Nie jest, to idealne rozwiązanie, ale tworzenie testów nawet dla istniejącego kodu jest lepszym rozwiązaniem niż brak testów. Proces refaktoryzacji wspartej TDD jest opisany w “Rozdział 31. Refaktoryzacja” w książce TDD. Sztuka tworzenia dobrego kodu.
Po co pisać testy?
Zacznę od tego, że brak testów może wskazywać na to, że nie rozumiemy tworzonego kodu źródłowego, bo dobre testy wymagają znajomość kodu, który testujemy. Jeżeli rozumiemy kod, który testujemy, to znaczy, że będziemy w stanie zmodyfikować go. Często powtarzam moim uczniom, uczennicom, jeżeli chcecie spać spokojnie, to piszcie testy jednostkowe. Kolega, koleżanka z zespołu dziesięć razy zastanowi się zanim zmodyfikuje nasz kod, bo testy mogą przestać działać i będzie trzeba je poprawić.
Jedyną stałą rzeczą w kodzie jest zmienność kodu. Testy pozwalają modyfikować istniejący kod bez obaw, że nasza zmiana coś popsuła w kodzie. Jeżeli tak będzie, to testy wykażą taki błąd i już na etapie tworzenia kodu będziemy w stanie wyłapać i poprawić taki błąd, a nie na produkcji. Unikniemy sytuacji z naszego ulubionego mBanku – niebezpiecznik.pl (5/8/2020).
Kto pisze testy?
W procesie tworzenia testów należy wyróżnić programistów oraz testerów. Dlaczego nie wystarczą testy pisane przez programistów? Powodów jest kilka, pierwszym z nich jest to, że programista testując swój kod wie jakie warunki i miejsca omijać w testowanym kodzie, no i oczywiście, kto będzie znajdował błędy w swoim idealnym kodzie? Testerzy często tworzą testy dla osób nietechnicznych, które chcą zweryfikować jak działa zamawiane oprogramowanie. Dodatkowo tester “dostaje wynagrodzenie” za znalezienie jak największej liczby błędów.
Programista
Testy napisane przez programistów weryfikują poprawność działania tworzonego kodu z perspektywy języka programowania, jak również logiki biznesowej aplikacji, np. wykonanie przelewu bankowego jest logiką biznesową aplikacji.
Programiści w większości przypadków tworzą testy automatyczne. Dla każdego testu należy zdefiniować dane wejściowe oraz oczekiwany wynik, aby zdefiniować takie dane oraz wynik musimy wiedzieć jaka jest logika naszej aplikacji. Innymi słowy, tworząc poprawne testy pokazujemy, że wiemy jak działa testowana przez nas aplikacja.
Tester
Tworzą testy, aby głównie zweryfikować logikę biznesową aplikacji oraz testują tzw. warunki brzegowe, np. czy można wykonać przelew na ujemną kwotę i/lub datę z przeszłości? Testerzy tworzą zarówno testy automatyczne jak również manualne.
Kategorie testów
Testy manualne
Polegają np. na klikaniu w stronę internetową banku w celu wykonania przelewu. Jeżeli tester znajdzie błąd podczas wykonywania przelewu zgłosi go – za pomocą systemu do zgłaszania błędów, np. JIRA – programiście, który będzie musiał taki błąd poprawić w późniejszym czasie, nie koniecznie od razu. Idealną sytuacją jest, w której tester posiada scenariusze testowe, które, to krok po kroku opisują, co należy zrobić, aby wykonać przelew bankowy. Na tej podstawie można odtworzyć sytuację, która wywołała błąd, w przeciwnym wypadku błąd może nie zostać nigdy odtworzony i naprawiony.
Testy automatyczne
Wymagają użycia narzędzia, za pomocą którego można zaprogramować, zautomatyzować sekwencję czynności, które doprowadzą np. do wykonania przelewu bankowego. Większość testów automatycznych tworzonych przez testerów jest testami integracyjnymi.
Do testów automatycznych testerzy mogą używać takie narzędzia jak Selenium (testy www), Postman (testy REST API) lub JMeter (testy wydajnościowe). Kroki niezbędne do wykonania testu powinny być spisane w scenariuszu testowym. Za pomocą ww. narzędzi tester nagrywa, koduje test automatyczny, który następnie jest odtwarzany dowolną ilość razy w dowolnym momencie na wcześniej zdefiniowanym zbiorze danych.
Z założenia testy tworzone przez programistów są testami automatycznymi. Do tworzenia takich testów programiści używają framework’ów do testowania kodu źródłowego, czyli klas języka Java. Najpopularniejszym obecnie framework’iem jest JUnit. Jak łatwo korzysta się z JUnit w IntelliJ napisałem wcześniej w tym artykule. Testy automatyczne tworzone przez programistę możemy podzielić na testy integracyjne i jednostkowe.
Zanim omówię testy kodu źródłowego z perspektywy programisty zachęcam do zapoznania się z informacjami o klasach w języku Java, Pierwsza klasa – kod Java, IntelliJ, krok po kroku oraz informacjami o metodach w języku Java, Działania w pierwszej klasie – kod Java, IntelliJ, krok po kroku. Testy kodu źródłowego pisane przez programistę testują metody w klasach.
JUnit test – praktyczny przykład
Środowiska programistyczne takie, jak IntelliJ domyślnie wspierają tworzenie testów dla naszego kodu. Wystarczy ustawić kursor na wybranej nazwie klasy i wcisnąć ALT+Enter, wyświetli nam się opcja “Create Test” i/lub wcisnąć ALT+Insert w dowolnym miejscu w kodzie klasy i wybrać opcję “Test…”. Następnie będziemy mogli wybrać bibliotekę do testów (na chwilę obecną domyślny jest JUnit5) oraz metodę, którą chcemy przetestować, będzie ona dostępna do wyboru na liście.
Test jednostkowy – co testować?
Programista pisząc testy jednostkowe, testuje poprawność działania metod w klasie, głównie metod publicznych. W jaki sposób testuje się poprawność działania metody? W języku Java metoda może przyjmować parametry, zwracać wynik i/lub rzucać wyjątek i właśnie te elementy są testowane przez programistę. Testowanie działania metody linijka po linijce nie miało by większego sensu.
Test jednostkowy – jak testować?
Mając powyższą wiedzę programista definiuje dane wejściowe do metody oraz sprawdza wartość zwracaną z metody. Dobrą praktyką jest podzielenie testu na sekcje given, when, then – nazwy są samo opisujące się. W tych sekcjach programista umieszcza logikę testu jednostkowego.
- W sekcji given powinna być klasa, którą testujemy oraz wartości dla parametrów testowanej metody – dane wejściowe – w tym przypadku BankService oraz BankAccount.
- W sekcji when powinna zostać wywołana metoda, którą testujemy transfer(), przekazujemy do niej wartości dla parametrów (fromBankAccount oraz toBankAccount), a następnie przypisujemy wartość zwracaną transferred.
- W sekcji then sprawdzamy wartość zwracaną z metody transfer() za pomocą mechanizmu assercji z framework’a JUnit – w tym przypadku assertFalse().
Test integracyjny
Testy integracyjne programista pisze dla wielu współpracujących ze sobą klas i ich metod, grupuje różne funkcje kodu w celu przetestowania tzw. pełnej ścieżki dla danego przypadku użycia, który może być opisany w scenariuszu testowym. W dużym uproszczeniu można powiedzieć, że w sekcji given będzie więcej obiektów (CurrencyConverterService i BankService), a w sekcji when będzie więcej wywołań metod (balance() i convert()), których wyniki będą wzajemnie przekazywane (BigDecimal balance i BigDecimal balanceInEuro).

Piramida testów

Na koniec umieszczę link do artykułu o piramidzie testów z praktycznym przykładem oraz obszernym wytłumaczeniem roli i znaczenia testów – https://martinfowler.com/articles/practical-test-pyramid.html.
