Skip to content

Witaj w Świecie Jutra!

  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
  • Home
  • Wszystko
  • Czym jest JUnit (i Mockito)?
  • Programowanie
  • Wszystko

Czym jest JUnit (i Mockito)?

Jakub Raczkowski 13 kwietnia 2024

Czym byłaby jakakolwiek aplikacja bez testów dowodzących, że spełnia założone wymagania? W dzisiejszym artykule z cyklu „Czym jest…?” skupimy się na frameworkach z dziedziny QA: JUnit, Mockito i im podobnych.

Uwaga! W tej serii zajmuję się opisowym przedstawieniem tematu, a celem jest zapoznanie z zagadnieniem w sposób luźny i zrozumiały dla nowicjusza. W związku z tym wiele elementów siłą rzeczy musi zostać pominiętych. Tych z was, którzy chcieliby się dowiedzieć więcej, zapraszam do źródeł na końcu artykułu.

Co powinien robić program?

Ktoś powie:
Co za idiotyczne pytanie! Oczywiście, że to do czego został stworzony! Kalkulator ma kalkulować, odtwarzacz filmów – odtwarzać filmy, a klient email odbierać i wysyłać maile.

No właśnie, sęk w tym, że to nie do końca prawda. Każda, ale to każda aplikacja, ma dwa zadania:

  1. Spełniać swoją funkcję.
  2. Nie spełniać żadnej innej funkcji.

A co ciekawe, ten drugi punkt jest tak samo ważny (o ile nie ważniejszy!) jak ten pierwszy.

Wyobraźcie sobie, że pobieracie skądś kalkulator, który kalkuluje – i robi to doskonale! – a jednocześnie kopie sobie bitcoiny dla jakiegoś cwaniaka. Albo klient email, który pięknie odbiera i cudownie wysyła maile… nie tylko do ustawionego odbiorcy, ale również wszystkich innych zapisanych kontaktów.

Żeby uniknąć takich i podobnych sytuacji, powstało coś takiego jak QA – Quality Assurance (ang. zapewnienie jakości). QA to zazwyczaj osobny dział w firmie gdzie pracują sami testerzy – co jednak nie zwalnia programistów z obowiązku pisania softu pozbawionego błędów. Robert Martin (aka Wujek Bob) w swojej książce „The clean coder” wielokrotnie powtarzał, że mottem profesjonalnego deva powinno być:

QA must find nothing!

(ang. Nie zostawiaj niczego dla QA!)

Współpraca programisty i testera nie zawsze jest przyjemna, ale to konieczność.

Ok, ale JAK właściwie testować aplikacje?

Na początku naszej drogi w kierunku zawodu programisty, testujemy głównie manualnie: odpalamy kodzik i sprawdzamy wszystkie opcje. W przytoczonym powyżej prostym kalkulatorze robilibyśmy po kolei: dodawanie, odejmowanie, mnożenie i dzielenie. Jeśli wyniki będą zgodne z tym co nauczyła nas podstawówka, to znaczy, że appka działa. Proste.

Sytuacja komplikuje się wraz z projektowaniem bardziej rozbudowanych programów. Jak dołożymy tam pierwiastki, potęgi, silnie, sinusy, cosinusy, zapamiętywanie wyników, funkcje… to takie manualne przetestowanie nowego commita zajmie nam kupę czasu. A to w konsekwencji sprawi, że będziemy to robić rzadko, np. raz na kilka godzin pracy, albo kilka dni…

…albo wcale.

Nie tędy droga. O ile testy manualne są jak najbardziej potrzebne – w obecnych czasach robi się je już na samym końcu, tuż PRZED* oddaniem efektów pracy klientowi.

(*) Albo jak pokazuje branża gamedev – już PO oddaniu efektów pracy klientowi. Nazywają to „dostęp Early Access” i za taką przyjemność przetestowania na wpół-działającej gry trzeba zapłacić, nierzadko jak z pełnoprawny produkt.

Aby testowało się przyjemnie, szybko i często, powstały liczne biblioteki z klasami i metodami to umożliwiającymi, wśród nich właśnie tytułowe JUnit oraz Mockito. Zanim jednak do nich przejdziemy, odpowiedzmy jeszcze na pytanie:

Ale CO testować?

Oj, rodzajów testów jest sporo! Powstała nawet specjalna infografika w postaci piramidy, która pokazuje hierarchię ważności i kolejność wykonywania poszczególnych rodzajów testów:

Piramida testów (źródło obrazka)

Jak widać, są tam różne typy testów, od jednostkowych (Unit tests), które nie bez powodu są podstawą piramidy, aż po testy rynkowe (Sensing the world) na samym szczycie. Wraz z przeprowadzaniem kolejnych rodzajów testów maleje wiara w przypuszczenia (assumptions) a rośnie pewność, że całość działa, dobrze razem współgra i poradzi sobie jako gotowy produkt (confidence in integrations).

W tym miejscu pewnie część z was zastanawia się dlaczego te etapy ubrano w obrazek piramidy, a nie na przykład strzałki/osi czasu. Wiele serwisów ponadto pokazuje te zależności w formie odwróconej piramidy – chodzi o to by pokazać, że im wyżej, tym testy trwają dłużej, a ich koszty rosną. Najtańsze testy są na samym dole – to te jednostkowe o których dziś mówimy. Jeśli będziemy na nich oszczędzać, to z pewnością zabulimy więcej gdzieś na wyższych etapach. Cóż, chytry dwa razy traci.

Jak dokładnie wyglądają poszczególne etapy testów?

  • testy jednostkowe (to są testy w których po prostu sprawdzamy czy dana metoda robi to co powinna, np. czy 2 + 2 to faktycznie jest 4)
  • testy integracyjne (tutaj sprawdzamy czy poszczególne elementy programu poprawnie ze sobą współpracują, np. połączenie z bazą danych albo komunikacja serwisów z kontrolerami)
  • testy akceptacyjne (te są często pisane albo przez samego klienta, albo na podstawie jego wymagań – moment w którym pozytywnie przechodzą wszystkie testy akceptacyjne jest uznawany za koniec rozwoju appki)
  • testy end2end (testy często manualne, sprawdzające poprawność działania od strony końcowego użytkownika)

Chociaż jako doświadczeni programiści będzie mogli wtrącić swoje trzy grosze na każdym z powyższych etapów, dzisiaj skupimy się na testach jednostkowych (i po trochu integracyjnych) z którymi z pewnością będą mieć styczność także junior developerzy.

Testowanie krok po kroku

Najprostszym sposobem na otestowanie wybranej metody jest dodanie zależności JUnit w mavenowym pom.xml (patrz: tekst o Mavenie):

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.2</version>
	//wersja biblioteki, do wyboru
    <scope>test</scope>
</dependency>

Kiedy już to zrobimy, wchodzimy na wybraną klasę w IntelliJ i wciskamy kombinację klawiszy:

CTRL + SHIT + T

Tym sposobem możecie stworzyć w pakiecie /test* klasę, której zadaniem będzie sprawdzenie czy metody klasy na bazie której powstała działają poprawnie.

(*) Mówimy o pakiecie Mavenowym i to bardzo ważne, bo mimo, że znajduje się w innym katalogu, to Maven (a wraz z nim IDE) traktuje taką klasę testującą zupełnie jakby była w pakiecie z klasą testowaną. A dzięki tej sztuczce możemy śmiało testować metody o dostępie pakietowym (bez modyfikatora 'public’)

Testy znajdują się w osobnym pakiecie.

Skoro klasa testująca jest już postawiona to warto byłoby tam coś wrzucić. Zanim to jednak zrobimy, spójrzmy jeszcze na parę zasad standaryzujących to jak pisać testy.

Nazewnictwo

Metoda testująca powinna mieć wymowną nazwę, czasem nawet bardzo długą, ale to bez znaczenia – ważne aby od razu wiadomo co jest testowane. Dla przykładu:

void add_firstArgumentOk_And_noSecond_throwsIllegalArgumentException()

Powyższa metoda testuje czy jeśli podamy pierwszy argument dodawania (firstArgumentOk) ale nie podamy drugiego (noSecond) to faktycznie zostanie wyrzucony wyjątek ’IllegalArgumentException’.

Struktura

O ile komentarze w kodzie produkcyjnym nie są mile widziane, o tyle przyjęło się, że w testach oddzielamy poszczególne części metody takimi komentarzami jak:

  • //given
  • //system under test
  • //when
  • //then

Sekcja ’given’ przygotowuje środowisko testowe: tutaj tworzymy zmienne i nadajemy wartości.

’System under test’ nie występuje tak często jak pozostałe – raczej tylko przy testowaniu bardziej rozbudowanych metod, gdzie najpierw trzeba zbudować obiekt który będziemy testować z elementów nakreślonych w 'given’.

W części ’when’ następuje użycie testowanej metody, natomiast w ’then’ porównanie (asercja) jej wyników z tym co faktycznie miała zwrócić.

Asercje

Najprostszy test wygląda tak, że najpierw używamy metody z argumentami z sekcji 'given’, a następnie porównujemy otrzymany wynik z tym czego oczekujemy.

//given
int x = 2; 
int y = 2;
//when
int sum = add(x,y);
//then
assertEquals(sum, 4);

W powyższym przykładzie metoda assertEquals() pochodząca z biblioteki JUnit sprawdza czy wartość zwracana przez metodę add(x,y) rzeczywiście równa się 2. Jeśli tak – test przeszedł i zaświeci się na zielono, w przeciwnym wypadku kolor czerwony oznaczający, że coś nie bangla.

Nasz test przeszedł.

Frameworki do testów

Póki co piszemy jedynie o bibliotekach JUnit – są najpopularniejsze i najłatwiejsze na start. Ale nie jedyne.

Świetnym uzupełnieniem JUnit jest Mockito. Słówko ’mock’ w języku angielskim oznacza 'przedrzeźniać’ albo 'podszywać się pod coś/kogoś’. I to jest mniej więcej funkcja Mockito, które głównie stara się ułatwić developerowi przygotowanie środowiska testowego (sekcja 'given’).

Często metoda, którą chcemy przetestować pobiera jakieś parametry. Jeszcze pal licho jak są tam jakieś Stringi albo typy proste. Gorzej jeśli są tam obiekty do stworzenia których potrzebujemy innych obiektów, do stworzenia których potrzebujemy innych obiektów, do stworzenia których potrzebujemy innych obiektów, do stworzenia których potrzebujemy innych obiektów…

…i tak dalej, i tak dalej.

W tym miejscu zamiast szukać dobrego miejsca na postawienie stołka i zawieszenie paska od spodni, programista może po prostu użyć metody Mockito i „podszyć się” pod wymagane obiekty:

NeededObject mockObject = mock(NeededObject.class);

I gotowe. W dodatkowych metodach Mockito możemy ponadto odpowiednio ustawić zachowanie tego zamockowanego obiektu, tak by jego atrybuty pasowały do naszych testów.


Na koniec

Jak z pewnością zauważyliście, dzisiejszy tekst już rozrósł się do granic możliwości, choć w założeniu miał jedynie na szybko opisać temat. Chciałem jeszcze dodać coś więcej o innych popularnych frameworkach, ale – aby nie przytłoczyć nawałem informacji – ograniczę się tylko do pojedynczych zdań:

  • AssertJ jest uzupełnieniem JUnit, daje dostęp do bardziej precyzyjnych asercji
  • TestNG to taki ulepszony JUnit pozwalajacy m.in. na grupowanie testów czy testowanie współbieżne
  • Spock, podobnie jak TestNG, chce wygryźć JUnit ze stołka lidera – jego plusy to łatwiejsza składnia (ale piszemy go w języku Groovy, który nieco różni się od Javy), wbudowane metody mockujące oraz możliwość testowania metod prywatnych
  • Selenium to już właściwie cała platforma skierowana nie tyle dla samych programistów co dla testerów QA, nastawiona na testy end2end

Uff. Na dzisiaj tyle i jak zwykle dziękuję za uwagę. W następnym odcinku odpowiemy na pytanie „Czym jest REST (i SOAP)?”.


Źródła:
Dlaczego wolę pisać testy w Spocku? YT/ANG
Seria wpisów o testowaniu w Javie (ANG)

Tags: java programming

Continue Reading

Previous: Czym jest SQL (i NoSQL)?
Next: Czym jest REST (i SOAP)?

Related Stories

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025

Ze świata

  • Antyweb
  • Kwantowo
  • Dwóch po dwóch
Europa ma swoje DNSy. Będziesz chciał z nich skorzystać
mObywatel szykuje prawdziwą bombę. Warto czekać!
Nintendo Switch 2 zrobiło to dobrze. Mam tylko wątpliwości, czy jest się z czego cieszyć
Tytuły anime to absurd. Ale winni są czytelnicy
Kto stoi za MacAllisterem? Marka z Castoramy pod lupą.
Dobra wiadomość! Nie trzeba kupować tego dodatku do Switcha, wystarczy smartfon
Głośnik Bluetooth w sensownej cenie. Najlepsze alternatywy dla JBL Charge.
T-Mobile nie uniknie wysokiej kary. Sąd stanął po stronie klientów
Elektronika na pokładzie samolotu. Zasady, o których musisz wiedzieć!
Energia kosmiczna. Jak w przyszłości będzie wyglądać zasilanie poza Ziemią?
Czy klawiatury mechaniczne są tylko dla komputerowych świrusów?
Wyciekł film promujący nowe urządzenie Garmin. Potwierdza przecieki
Weekend z darmowymi hitami. Warto skorzystać już teraz
Budowlańcy mogą mieć problem. Te cacka zabiorą im robotę
Dexter z Leroy Merlin: Sprawdzamy, co kryje się za niską ceną
Nintendo pokazuje gdzie ma swoich fanów. Obrzydliwy skok giganta na kasę
YouTube przegina. Tam reklam jeszcze nie było
Nintendo wyciśnie z ciebie każdy grosz. Spełnił się najgorszy koszmar Switcha 2
W dysku protoplanetarnym znaleziono składnik życia. To nie przypadek
Blokady reklam znów na celowniku. Google nie chce się poddać
Ocalić od zapomnienia
Ostatni kwant
ALH 84001 – meteoryt, o którym mówiono nawet w Białym Domu
HESS zarejestrował kosmiczny elektron o niespotykanej energii [Phys. Rev. Lett.]
Matka ciemnej materii – recenzja biografii “Vera Rubin. Życie”
Satelita, który zerwał się ze smyczy
Wiadomość od Carla Sagana do przyszłych eksploratorów Marsa
Ile najdłużej może trwać zaćmienie Słońca?
Nowa największa liczba pierwsza ma ponad 41 milionów cyfr [GIMPS]
Pulsar 4U 1820-30 wykonuje 716 obrotów na sekundę [AJ]
Nasze podsumowanie Comic Con Baltics 2025
Mała wielka mysz. Glorious Model O 2 mini – recenzja
Tak było na Comic Con Baltics 2025 w Wilnie (Relacja)
O przedsprzedaży Pixel 9a w samochodzie – Odcinek #122
Obejrzeliśmy Ukryty Poziom na raz – No Movie Ci
Premiera Nintendo Switch 2, seriale, i piwniczne artefakty – Odcinek #121
Ludzieee, wy tego używacie? Recenzja klawiatury Trust GXT 867 Acira
Sympatyczny mały flagowiec. Samsung Galaxy S25 – recenzja
Recenzja pionowej myszy Natec Crake 2. Się wziął gruby i nawrócił
Podsumowanie 2024 roku: Gry, Smartfony, Seriale – Odcinek #120

To może cię zainteresować:

Mageege Moon104 – test niskoprofilowego mechanika
  • Sprzęt

Mageege Moon104 – test niskoprofilowego mechanika

11 marca 2025
Przebranżowienie cz.4
  • Programowanie

Przebranżowienie cz.4

27 lutego 2025
Smartfon Jutra
  • Sprzęt

Smartfon Jutra

15 lutego 2025
Czym jest Swagger?
  • Programowanie

Czym jest Swagger?

22 lipca 2024
  • Technologie jutra
  • Sprzęt jutra
  • Aplikacje jutra
  • Programowanie
  • Księga Drogi
  • Renowacja
  • Różności
  • Archiwum
  • Autor
Copyright © All rights reserved. | DarkNews by AF themes.