Kiedy warto używać Mockito?

2

Kiedy warto mockować rzeczy przez mockito zamiast mockować poprzez napisanie dodatkowego interface z dwiema implementacjami (zwykłą i fakową/stubową)? Zazwyczaj staram się robić to drugie, ale widzę, że wszędzie, zawsze ludzie polecają, żeby zamiast się "męczyć" po prostu zamockować.

(jeśli mod uzna, to można przenieść do IO)

6
  1. Nigdy, bo easymock masterrace :P
  2. Prosta sprawa -> jak skomplikowany jest setup tego mockowanego obiektu i w ilu testach ci potrzebny? Jeśli jest skomplikowany to może warto zrobić z tego osobną implementacje, jeśli potrzeba go w wielu testach to też. Jeśli caly setup to mockowanie jednej metody w jakimś jednym teście, to nie ma sensu bawić się w pisanie tego ręcznie.
0

To zależy czy chcesz zrobić stuba czy mocka. Jeśli to pierwsze, to w pierwszej kolejności rozważyłbym użycie fake’a, czyli tak jak napisałeś. Jeśli mock, czyli interesują mnie interakcje, to wtedy Mockito. Oczywiście musisz uważać na overmocking oraz nie mockować nie swoich typów (https://maksimivanov.com/posts/dont-mock-what-you-dont-own/).

Ja za każdym razem, kiedy mam użyć mocka zastanawiam się, czy na pewno tego potrzebuję. W większości przypadków i tak potrzebujesz stuba.

1

nie mockować nie swoich typów

To jakaś bzdura. Mockujesz to od czego chcesz się w danym teście odciąć, niezależnie od tego do kogo ta klasa należy. Chcesz przetestować funkcjonalność X przy założeniu, że inne komponenty działają w przewidywalny sposób. "Całość" i tak należy przetestować integracyjnie a potem e2e więc argument, że dostaniemy zielone testy bo źle zaprogramowaliśmy mocka jest inwalidą. Dostaniemy zielone testy, które nie sprawdzają działania biblioteki Y i dobrze! Bo nie to mają sprawdzać!
Wrappowanie wszystkiego tylko po to żeby mieć "swoje klasy" to chyba jak komus płaca od linijki kodu. Jak chce sie komunikować z serwisem X i mają libkę z klientem, to poza sytuacjami gdzie faktycznie chcemy jakoś sobie "rozszerzyć" tego klienta, nie ma sensu go wrappować własnymi klasami które będą tylko proxować wywołania w imie jakiejś idiotycznej zasady żeby mieć "swój kod". To coś jak robienie do wszystkiego interfejsów, mimo że wiemy, że będzie tylko jedna implementacja.
A jeśli teraz chce przetestować jednostkowo logikę, która opiera się na wyników z takiego klienta to nie widzę żadnego problemu, żeby w teście jednostkowym zamockować sobie odpowiedź (ale uwaga: zrobie też test integracyjny który będzie stawiać jakiegoś fejkowego http serwera udającego serwis X).
@Charles_Ray ten ziomek od tego bloga to jakiś uber koks MVP czy randomowy blog z neta? Bo wiesz, nie we wszystko co piszą w internecie trzeba wierzyć...

1

Testami pierwszej kategorii powinny być testy jednostkowe do klas, które realizują przypadki biznesowe. Dla mnie jednostka to przypadek użycia. Zwykle w kodzie staram się by to była klasa z jedną metodą np. Either<User, Error> UserRegistrationCommand::execute(User user)
W Javie bardzo wiele możemy sobie postawić 5 linijkami kodu. Bazę H2, serwer HTTP, katalog z plikami etc. Jeżeli się nie da to dopiero stosuję mockito i tylko wtedy. Nigdy nie mockuję kolaboratorów klasy.

Zalety takiego podejścia:

  1. Testy pisane są dla stabilnych interfejsów i sa odporne na refactoring,
  2. Testy są niezależne od implementacji. Interesuje mnie efekt w bazie, a nie czy ktoś zawołał metodę X::x()
  3. Jak na prod się coś wywali to mogę od razu przenieść przypadek do testów.
  4. Wciąż nie stawiam całej aplikacji, a więc testy są szybkie.

Wady:

  1. Podejście gryzie się z frameworkami dependency injection jak Spring.

Jeżeli czuję, że gdzieś niżej jest jakiś ważny algorytm to dodatkowo tworzę testy per tą klasę. To już w zależności od poczucia. Nigdy nie stosuję automatycznego podejścia 1 klasa - 1 test.

7

Mockito - prawie nigdy.

Wbrew temu co napisano powyżej mockowanie własnych klas to dla mnie przeważnie głupota (są wyjątki, ale nieczęste).

Jeśli już czasem mockito się przydaje to na mockowanie zewnętrznych serwisów - nie mój zespoł je robi, więc na wszelki wypadek mam mocka, który jakoś "dowodzi", że nasza częśc jest poprawna.
Ale i tak często warto napisać mocka ręcznie (bo łatwiej użyć wielokrotnie).
W jeddnej firmie wywalenie mockito i napisanie ręcznych mocków dawało nam mocno widoczne oszczędności na ilości kodu w testach. Po prostu masowe użycie Mockito (Mocksturbacja) prowadzi często do całych serii powtarzalnych mockito.when - nawet nie widać, że ten kod się powtarza.

0

Trochę nie odpowiada to na pytanie, ale ogólnie w temacie testów polecam poczytać: https://testing.googleblog.com/

0

Jak już polecamy, to nie może zabraknąć klasyka: https://leanpub.com/badtestsgoodtests
Polecam!

0

Wg mnie sprawa wyląda tak:

  • możemy mockować interfejsy wstrzykiwane do klas (np. poprzez frameworki/biblioteki do DI takie jak Spring, Dagger itd.) - gdyby tego nie robić, trzeba by odwzorować całą hierarchię zależności w projekcie za pomocą stubów, co mogłoby być żmudnym zajęciem w przypadku złożonego projektu i po prostu stratą czasu
  • nie powinniśmy mockować klas reprezentujących model danych - należy je stubować, ponieważ mockowanie może prowadzić do false-positivów w testach, a tego typu klasy i tak nie powinny mieć wstrzykiwanych zależności
4

mysle ze raczej warto unikac mockow. w praktyce jest to czasem niemozliwe bo ludzie/libki z ktorymi przychodzi nam pracowac raczej lubia miec kod wymagajacy [power]mockowania. przy kompletnie nowym kodzie najlepiej projektowac go tak zeby dalo sie zamiast mockow uzywac rzeczywistych parametrow wesciowych/wyjsciowych, w przeciwnym wypadku zamiast testowac funkcjonalnosc spedzamy 90% czasu na pieprzeniu sie z mockami ;)
kluczowymi wydaja mi sie tutaj 1) zapewnienie przynajmniej wzglednej niemutowalnosci parametrow 2) dobre okreslenie odpowiedzialnosci struktur 3) redukcja lub kompletna eliminacja efektow ubocznych

0

Może lekki odkop, ale zastanawiam się jak konkretnie miałoby wyglądać mockowanie serwisu ręcznie (implementacja) zamiast używania mockito.

Zakładając np że mamy jakiś CustomerService i w nim metode fetchCustomerData(). Metoda fetchCustomerData() w zależności od logiki/przekazanych parametrów może zachować się np. na 3 różne sposoby (zwraca dane, nie ma takiego customera, dane są niepełne).
W jaki sposób mogę sobie to elastycznie mockować w zależności od przypadku który chce przetestować?
Czy wiąże się to z Implementacją trzech mocków tj. CustomerServiceMock1, CustomerServiceMock2, CustomerServiceMock3 w których każdy z nich obsługiwał by jeden z wcześniej wymienionych przypadków?

Czy dobrze zrozumiałem ideę? Jeśli nie to proszę o wytłumaczenie, ewentualnie pokazanie na przykładzie.

1
Vincent_zyx napisał(a):

Może lekki odkop, ale zastanawiam się jak konkretnie miałoby wyglądać mockowanie serwisu ręcznie (implementacja) zamiast używania mockito.

Zakładając np że mamy jakiś CustomerService i w nim metode fetchCustomerData(). Metoda fetchCustomerData() w zależności od logiki/przekazanych parametrów może zachować się np. na 3 różne sposoby (zwraca dane, nie ma takiego customera, dane są niepełne).
W jaki sposób mogę sobie to elastycznie mockować w zależności od przypadku który chce przetestować?
Czy wiąże się to z Implementacją trzech mocków tj. CustomerServiceMock1, CustomerServiceMock2, CustomerServiceMock3 w których każdy z nich obsługiwał by jeden z wcześniej wymienionych przypadków?

Czy dobrze zrozumiałem ideę? Jeśli nie to proszę o wytłumaczenie, ewentualnie pokazanie na przykładzie.

Na przykładzie - to nigdy bym nie mockował tego CustomerService. Po prostu odpaliłbym na testowaj bazie (mockowa h2 in mem), która dla id =1000 ma dane, dla id=1001 nie ma nic w bazie, a dla id =1002 ma dane niepełnie.

Gdyby to CustomerService było klientem Rest service (a nie bazy danych) - to można użyć WireMocka.

0
jarekr000000 napisał(a):
Vincent_zyx napisał(a):

Może lekki odkop, ale zastanawiam się jak konkretnie miałoby wyglądać mockowanie serwisu ręcznie (implementacja) zamiast używania mockito.

Zakładając np że mamy jakiś CustomerService i w nim metode fetchCustomerData(). Metoda fetchCustomerData() w zależności od logiki/przekazanych parametrów może zachować się np. na 3 różne sposoby (zwraca dane, nie ma takiego customera, dane są niepełne).
W jaki sposób mogę sobie to elastycznie mockować w zależności od przypadku który chce przetestować?
Czy wiąże się to z Implementacją trzech mocków tj. CustomerServiceMock1, CustomerServiceMock2, CustomerServiceMock3 w których każdy z nich obsługiwał by jeden z wcześniej wymienionych przypadków?

Czy dobrze zrozumiałem ideę? Jeśli nie to proszę o wytłumaczenie, ewentualnie pokazanie na przykładzie.

Na przykładzie - to nigdy bym nie mockował tego CustomerService. Po prostu odpaliłbym na testowaj bazie (mockowa h2 in mem), która dla id =1000 ma dane, dla id=1001 nie ma nic w bazie, a dla id =1002 ma dane niepełnie.

Gdyby to CustomerService było klientem Rest service (a nie bazy danych) - to można użyć WireMocka.

Fajnie, tylko ten ten CustomerService to właśnie rest api, nie miałem na myśli mockowanie swoich 'rzeczy' w kodzie:)

Sugerujesz używanie Wiremocka... Czyli w takich złożonych przypadkach nie warto się bawić w implementacje poszczególnych mocków?

0

A co w przypadku, gdybym miał kilka instancji tego samego rest serwisu, różniące się tylko urlem bo endpoint path byłby taki sam, przez co nie byłbym wstanie stworzyć 2 różnych stubow wiremockowych, a chciałbym żeby requesty do instancji leciały równolegle i jedna instancja zwracała 200 a druga 500? Tak trochę offtop ale jakbyście użyli wiremocka do tego? Postawić 2 serwery symulujące 2 instancje?

0
Vincent_zyx napisał(a):

Czy wiąże się to z Implementacją trzech mocków tj. CustomerServiceMock1, CustomerServiceMock2, CustomerServiceMock3 w których każdy z nich obsługiwał by jeden z wcześniej wymienionych przypadków?

Dokładnie tak. Dlatego mockito jest przydatne bo zrobisz to jedną linijką. Inaczej musisz zrobić 3 implementacje interfejsu i nadpisać metody. Ale zaraz tutaj się zjedzie stado hejterów którzy piją tylko czystą :D

1
Properties napisał(a):

Tak trochę offtop ale jakbyście użyli wiremocka do tego? Postawić 2 serwery symulujące 2 instancje?

Problem jest troche wymyśliny, ale nie ma problemu. Tak samo jak nie ma problemu zrobic w given dwóch hashmap testowych, tak samo sobie 2 wiremocki (chyba) możesz postawic. (Chyba, bo raczej nie testowałem takiej konstelacji).

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.