In this article, I will describe why testing application code is so important, describe how to create different types of tests, and show an example of a JUnit test for Java. I always say, if you want to sleep soundly, write application code tests. By tests I mean various types of tests, e.g. unit tests, integration tests, automatic and manual tests. There are several techniques for writing tests.
Preface
People are divided into those who write the tests and those who will write them. We all know what the production application tests performed by mBank looked like - niebezpiecznik.pl (5/8/2020) – we don't do that, we want to avoid it.
Techniques for writing tests
At the beginning I mentioned different types of tests, I will discuss them in more detail later. Various test writing techniques can be added to the test types.
TDD – Test Driven Development
The most popular test writing technique is Test Driven Developmnet – TDD. The TDD technique involves writing tests first, and then writing the actual class that we are testing. This forces us to write tests for the code we create. TDD develops a good habit thanks to which our source code has tests "right away". I recommend the book TDD. The art of writing good code.
"Technique" of adding tests
Another "technique" for writing tests is to add tests to existing source code during refactoring or due to a lack of tests. It's not a perfect solution, but creating tests even for existing code is a better solution than no tests at all. The TDD-supported refactoring process is described in "Chapter 31. Refactoring" in the book TDD. The art of writing good code.
Why write tests?
Let me start by saying that the lack of tests may indicate that we do not understand the source code being created, because good tests require knowledge of the code we are testing. If we understand the code we are testing, it means we will be able to modify it. I often tell my students that if you want to sleep soundly, write unit tests. My colleague will think ten times before modifying our code, because the tests may stop working and will have to be corrected.
The only constant thing in code is code variability. Tests allow you to modify existing code without worrying that your change will break something in the code. If this is the case, the tests will show such an error and we will be able to detect and correct such an error already at the stage of code creation, not in production. We will avoid the situation with our favorite mBank – niebezpiecznik.pl (5/8/2020).
Who writes the tests?
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.
Programmer
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
Manual tests
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.
Automatic tests
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().

Integration test
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.