Wyślij zapytanie Dołącz do Sii

W 2017 roku język Kotlin został ogłoszony jednym z oficjalnych języków programowania na platformie Android. Dzięki tej decyzji w bardzo krótkim czasie stał się popularny i uwielbiany przez programistów. Jego składnia znacząco różniła się od języka JAVA – na tyle, aby część programistów zaczęła zastanawiać się, czy jego możliwości da się wykorzystać również w testach.

Z czasem zaczęły powstawać biblioteki do pisania testów, w których wykorzystywano możliwości języka Kotlin. Jedną z nich jest właśnie biblioteka MockK, którą przybliżymy w artykule.

Konfiguracja biblioteki MockK

Poniżej znajduje się konfiguracja biblioteki:

Konfiguracja bliblioteki MockK
Ryc. 1 Konfiguracja bliblioteki MockK

Po co testować? 

Na początku możemy sobie zadać pytanie – po co w ogóle są nam potrzebne te testy? Na potrzeby artykułu napisaliśmy kod (dodany poniżej), który służy do pobierania lokalnego czasu w milisekundach. Możemy być przekonani, że jest on przygotowany poprawnie i zawsze będzie działać.

I być może tak rzeczywiście będzie, ale, będąc profesjonalistami, musimy upewnić się podwójnie, że nawet po edycji wszystko zadzieje się tak, jak sobie to założyliśmy. Właśnie dlatego powstają testy.

kod przygotowany na potrzeby artykułu

Jak testować z użyciem biblioteki MockK?

Aby zamockować nasz DateLocalSource, wykorzystujemy konstrukcję mockk<typ obiektu> {}, gdzie w nawiasach klamrowych określamy zachowania metod w danym obiekcie. Dzięki słówku kluczowemu „every”, możemy określić, co dana metoda ma nam zwrócić w przypadku jej wywołania. Osiągamy to w poniższym przykładzie dzięki słówku kluczowym „returns“, ale nie jest to jedyna opcja.

fragment kodu

Jeżeli chcemy zdefiniować bardziej zaawansowane zachowanie, oparte chociażby na argumentach przekazanych do metody, powinniśmy użyć „answers”, a gdy potrzebujemy, by ta metoda rzucała nam wyjątkiem, wystarczy użyć „throws”.

Są to podstawowe i najczęściej występujące słowa kluczowe, ale MockK oferuje ich znacznie więcej. To niektóre z nich:

  • just Runs – definiuje, że metoda zwraca Unit,
  • just Awaits – definiuje, że metoda nigdy nic nie zwraca,
  • returnsMany – pozwala na definiowanie sekwencji wartości, które mają być zwracane przez wywoływaną metodę w kolejnych wywołaniach,
  • throwsMany – pozwala na definiowanie sekwencji wyjątków, które mają zostać rzucone.

Jak sprawdzić, czy metoda się wywołała?

Wiemy, jak zamockować to, co ma zwrócić dana metoda. Ale jak sprawdzić, czy w ogóle ta metoda się wywołała? Z pomocą przychodzi nam „verify”. Wystarczy skorzystać z konstrukcji verify { zamockowanyObiekt.metodaKtórejWywołanieChcemySprawdzić() }, aby test przechodził tylko wtedy, gdy podana metoda zostanie wywołana.

Warto pamiętać, że gdy wykorzystujemy zwykłe „verify”, to metoda musi zostać wywołana przynajmniej raz, by weryfikacja przebiegła pomyślnie. Użycie dodatkowych słówek kluczowych używanych w nawiasach – jak „exactly” – zostanie wytłumaczone w późniejszej części artykułu.

fragment kodu

Korutyny

Warto wspomnieć o jednej z większych zalet biblioteki, a dokładniej o tym, że MockK wspiera jeden z filarów języka Kotlin – korutyny.

W przykładowych testach naszego kodu do pobierania czasu ewidentnie widać, że metody typu „suspend” mają osobny pakiet funkcji do mockowania oraz weryfikacji danych (przedrostek „co”). Dzięki temu rozwiązaniu łatwo da się zauważyć, gdzie używamy takiego typu metod, gdyż z racji specyfiki budowy, wymagają one innego traktowania niż zwykle metody.

Nasuwa się więc wniosek: używając MockK, nie musimy martwić się o metody „suspend”, ponieważ wystarczy pamiętać o dodaniu przedrostka „co”, który pozwoli na ich bezproblemową obsługę.  

Domyślnie czy niedomyślnie?

Pierwszą bolączką, która będzie wymagała naszej decyzji, jest argument „relaxed” używany przy definicji mockowanego obiektu. Biblioteka MockK domyślnie NIE mockuje wszystkich metod danego obiektu. Ale w sumie jest to jej wielka zaleta!

Wyobraźmy sobie sytuację, że tworzymy nową metodę zwracającą typ Unit i przez pomyłkę umieszczamy ją w miejscu, w którym nie powinno jej być. W takim przypadku użycie „relaxed = True” spowoduje, że test nie będzie w stanie wykryć nieprawidłowości, gdyż metoda będzie automatycznie zamockowana.

W każdej innej sytuacji ręczne wpisane każdego „every” bądź „coEvery” dla naszych metod zabezpieczy nas, ponieważ każda niezamockowana metoda zwróci błąd testu. Z tego powodu uważamy, że powinniśmy używać tego argumentu z głową i tylko w przypadku chęci przetestowania konkretnych sytuacji, gdzie nie zwracamy uwagi na inne metody.

fragment kodu

Nie tylko prosta weryfikacja

„Verify” dzięki możliwości podania argumentów jest bardzo elastycznym narzędziem do weryfikacji wywołań metod. Oto najczęściej wykorzystywane:

  • (exactly = n) – metoda wywołana dokładnie n razy​,
  • (atLeast = n) – metoda wywołana minimum n razy​,
  • (atMost = n) – metoda wywołana maksimum n razy.
fragment kodu

MockK oferuje nam jeszcze dodatkowe opcje weryfikowania, które zostały przedstawione na przykładach poniżej.

fragment kodu

fragment kodu
  • verifyAll – sprawdza, czy wszystkie zadane metody wywołały się bez względu na kolejność​,
  • verifySequence – sprawdza, czy wszystkie zadane metody wywołały się zgodnie z podaną sekwencją​,
  • verifyOder – sprawdza, czy wszystkie zadane metody wywołały się w podanej kolejności​,
  • wasNot Called – sprawdza, czy mock (lub lista mocków) nie wywołał się w ogóle.

A co z metodami statycznymi?

Statyczne metody to byt, który wywołuje mieszanie uczucia. Należy się jednak zgodzić, że są momenty, w których jest to całkiem przydatne rozwiązanie. Dlatego wydaje się rozsądne, że biblioteka MockK postanowiła domyślnie wesprzeć ten sposób pisania kodu.

fragment kodu

fragment kodu

We wskazanym przykładzie pomyślnie zamockowalismy statyczną metodę „getInstance()” będącą częścią klasy Calendar. Gdy już jej nie potrzebujemy, używamy metody „unmockkStatic(Calendar::class)”, która cofa zamockowanie klasy.

Sposób na prywatne metody?

Czy z architektonicznego punktu widzenia powinno testować się działanie/wywołanie prywatnych metod? To również kwestia sporna i zależna od sytuacji.

Niemniej, bardzo dobrze, że MockK także wspiera to rozwiązanie i nie wymaga przy tym adnotacji @VisibleForTesting. Wystarczy użyć spyka z parametrem „recordPrivateCalls” ustawionym na „true”, co umożliwi nam zamockowanie prywatnej metody w sposób pokazany poniżej.

fragment kodu

O spyku należy jednak napisać nieco więcej, gdyż to rozwiązanie daje nam duże pole manewru. W domyśle operujemy na realnym obiekcie, a nie jego mocku, przy czym w dalszym ciągu możemy cześć metod zamockować, podczas gdy reszta będzie operowała na realnym kodzie.

  • (recordPrviateCalls = true) – umożliwia zamockowanie prywatnych metod​,
  • mock[„accelerate”]() – ta konstrukcja pozwala zamockować prywatną metodę accelerate().

MockK czy Mockito?

Część osób może zapytać, czym jest w ogóle Mockito. Mockito to biblioteka, która tak jak MockK umożliwia testowanie, z tą różnicą, że stosuje ona bardziej klasyczną składnię Javy, co dla niektórych może być minusem. Szczególnie, gdy na co dzień piszą w Kotlinie. W takim przypadku składnia MockK powinna im bardziej przypaść do gustu, ponieważ jest bardzo podobna do tej używanej w języku Kotlin.

Co szczególnie przemawia na rzecz używania MockK zamiast Mockito? Argumenty przedstawimy w formie tabelki.

MockKMockito
Nie mockuje domyślnie wszystkich metodMockuje domyślnie wszystkie metody
Wbudowane wsparcie dla korutynBrak wbudowanego wsparcia dla korutyn
Wbudowane mockowanie statycznych metodUtrudnione mockowanie statycznych metod
Kod jest bardziej czytelny i przystępnyKod jest mniej czytelny
Tab. 1 MockK czy Mockito – zalety i wady narzędzi

Patrząc na plusy MockK w stosunku do Mockito, naszym zdaniem warto zapoznać się z tą biblioteką, szczególnie, że jest już coraz szerzej stosowana w projektach komercyjnych i w niedługim czasie może całkowicie wyprzeć Mockito.

Podsumowanie

Biblioteka MockK oferuje bardzo przyjemny dla oka, wyjątkowo czytelny sposób pisania testów. Idealnie nadaje się do testowania aplikacji pisanych w Kotlinie. Wypada jeszcze lepiej, gdy do gry wkracza razem z biblioteką Kotest ze swoimi kotlinowymi rozwiązaniami typu infix (które z resztą użyliśmy w przykładowej aplikacji napisanej przez nas na potrzeby artykułu. Link do repozytorium, w którym jest udostępniona ta aplikacja możecie znaleźć poniżej w źródłach).

W artykule staraliśmy się skupić na podstawach, gdyż oczywiste jest, że możliwości biblioteki jest dużo więcej. Dlatego zachęcamy do sprawdzenia dokumentacji biblioteki MockK, która również stoi na wysokim poziomie. Po takiej lekturze migracja będzie zdecydowanie mniej groźna niż nam się wydaje 😊

Materiały źródłowe

5/5 ( głosy: 8)
Ocena:
5/5 ( głosy: 8)
Autorzy
Avatar
Paweł Krzemiński

Początkowo – redaktor, potem z chęci tworzenia – twórca menadżerskich gier żużlowych. Od blisko 18 lat wielki pasjonat sztuki programowania, przechodząc sukcesywnie przez języki C, C++, C#, Swift, JS, Java. W końcu zdecydował się na obszar aplikacji mobilnych na system Android, czyli język Java, a potem Kotlin. Szeroki wachlarz znajomości języków pozwala mu w szybkim tempie dostosować się to technologii i wymagań w tworzonym projekcie. Ostatnim realizowanym przez niego komercyjnie projektem był projekt dotyczący platformy Android TV.

Avatar
Mateusz Suska

Pasjonat tworzenia aplikacji mobilnych, który koncentruje się na rozwijaniu swoich umiejętności i zdobywaniu doświadczenia w tej dziedzinie. Aktualnie kończy studia magisterskie na kierunku Informatyka na KUL oraz ukończył warsztaty z programowania aplikacji mobilnych dla systemów Android, co daje mu solidne podstawy w tworzeniu mobilnych rozwiązań. Niezmiennie dąży do poszerzania swojej wiedzy, uczestnicząc w różnych kursach oraz samodzielnie pisząc aplikacje w języku Kotlin. Jego zapał i profesjonalizm w działaniu są widoczne w licznych projektach, m.in.: realizowanym we współpracy z jednym z klientów Sii projektem dotyczącym platformy Android TV.

Zostaw komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Może Cię również zainteresować

Pokaż więcej artykułów

Bądź na bieżąco

Zasubskrybuj naszego bloga i otrzymuj informacje o najnowszych wpisach.

Otrzymaj ofertę

Jeśli chcesz dowiedzieć się więcej na temat oferty Sii, skontaktuj się z nami.

Wyślij zapytanie Wyślij zapytanie

Natalia Competency Center Director

Get an offer

Dołącz do Sii

Znajdź idealną pracę – zapoznaj się z naszą ofertą rekrutacyjną i aplikuj.

Aplikuj Aplikuj

Paweł Process Owner

Join Sii

ZATWIERDŹ

This content is available only in one language version.
You will be redirected to home page.

Are you sure you want to leave this page?