Czemu używacie mockito/innych libek do mocków, zamiast fake objectów?

1

Ja traktuję mocki jako łatwy sposób na stworzenie tanich i lekkich fake'ów, być może projekt jest warty tworzenia do każdego testCase indywidualnych i szczegółowych prawdziwych Fake'ów.
Jeżeli mam jakiś obiekt, który wiem, że będę wykorzystywał w wielu testach to najczęściej tworzę takiego prawdziwego i współdzielonego Fake już ręcznie pisanego.

Tylko dlaczego utrzymanie wielu fake'ów ręcznie pisanych ma być łatwiejsze niż utrzymanie fake'ów tworzonych z użyciem biblioteki mockującej?
Wydaje mi się, że nikt nie chce testować implementacji fake'ów jakoś bardzo szczegółowo, conajwyżej czy jakaś dana metoda została zawołana.

Aaaa i ostatnia rzecz, jestem zwolennikiem nie wydzielania interfejsów jeżeli nie ma takiej potrzeby, tzn: jest planowana tylko 1 implementacja, implementacja będzie napisana w tym samym module, nigdzie nie będzie użyte castowanie na ten typ interfejsu. W takim wypadku mock pozwala mi stworzyć szybko fake z mozliwoscia nadpisania metody i weryfikacji wywołań, bez martwienia się o zależności tej klasy, czy one rosną czy nie rosną.

2

Nie po to tworzę implementacje interfejsów aby później używać mockito albo robić fake'y. Niby są przypadki, gdzie integrujemy się z zewnętrznymi systemami i tam mogło by to zdać egzamin, ale zazwyczaj są lepsze rozwiązania, jakieś testcontainers, mockwebserver itd. 100 razy bardziej wolę jak jest 1 test bez mockito lub fake'ów, niż 10 testów z ich użyciem.

2

Jak już jesteśmy w temacie testów to klasyczny shameless plug -> piszcie testy tak: https://github.com/Pharisaeus/almost-s3/blob/master/test/src/test/java/net/forprogrammers/almosts3/test/DownloadTest.java#L13

Kto jest w stanie na podstawie tego kodu stwierdzić czy pod spodem są mocki, fake, wiremocki czy jeszcze cos innego? ;) Jak ktoś będzie chciał to wymieni implementacje w DSLu na inną i podmieni jedno na drugie, a wszystkie testy pozostaną bez zmian.

0

Tylko dlaczego utrzymanie wielu fake'ów ręcznie pisanych ma być łatwiejsze niż utrzymanie fake'ów tworzonych z użyciem biblioteki mockującej?

No właśnie przez kontekst które fake'i dodają.

Jakbyś miał interfejs BankAccount, to co innego jest zobaczyć w teście fake'i:

  • new AccountConstantMoney(5000)
  • new AccountWithLoan(-100)
  • new AccountBlockedTransactions()
  • new AccountEmpty()
  • new TestAccount(), testAccount.lastTransaction()

...a czym zupełnie innym jest zobaczyć

  • when(accountConstantMoney.getMoney()).thenReturn(5000);
  • when(accountWithLoan.getSummaryMoney()).thenReturn(-100)
  • when(accountBlockedTransactions.pay(500)).thenThrow(new BlockedTransaction())
  • when(emptyAccount.getMoney()).thenReturn(0)
  • verify(testAccount).perform(lastTransaction).

Dodam, że te wartości nie są jedynymi w teście, jest takich więcej, niektóre są parametryzowane, niektóre są zależne od innych wartości.

0

@TomRiddle: to jest demagogia. Stawiasz w opozycji: new AccountConstantMoney(5000) i when(account.getMoney()).thenReturn(5000), mimo, że tak naprawdę można ten kontekst nadać - when(accountConstantMoney.getMoney()).thenReturn(5000).

4

@TomRiddle: Twój przykład jest tendencyjny, przecież tak samo możesz wydzielić te wszystkie when do nazwanej metody.

Problemem nie jest używanie mocków, problemem jest to, że ludzie piszą nieczytelne testy. Zamiast w każdym pisać serię when, lepiej jest zrobić DSL podparty mockami i autofixturem, i to wszystko. Używanie bądź nie mocków powinno być szczegółem implementacyjnym, jeżeli chcę zrobić zaślepkę X, to nie interesuje mnie, czy jest to robione ręcznie czy mockiem, ja tylko wołam metodę zaślepX. Tak samo jeżeli chcę sprawdzić interakcję, to nie interesuje mnie, czy pod spodem jest verify, czy jakiś magiczny assert na prywatnym stanie ręcznie klepanego fake'a, ja tylko piszę verifyInteractionY.

0
rad1317 napisał(a):

Nie po to tworzę implementacje interfejsów aby później używać mockito albo robić fake'y.

A co z interfejsami, których nie implementujesz?

Niby są przypadki, gdzie integrujemy się z zewnętrznymi systemami i tam mogło by to zdać egzamin, ale zazwyczaj są lepsze rozwiązania, jakieś testcontainers, mockwebserver itd.

Możesz pokazać jak przy użyciu tych narzędzi mockować SDK zapisujące do KV albo tworzące mikroserwis, wstawić dane do bazy albo odpalić przez API jakiś CI pipeline? (Tylko pamiętaj, że jak robię task biznesowy, to po prostu wywołuję metodę z jakimiś danymi, ja nie chcę nawet wiedzieć jak wygląda interakcja z tym API.)

TomRiddle napisał(a):

Tylko dlaczego utrzymanie wielu fake'ów ręcznie pisanych ma być łatwiejsze niż utrzymanie fake'ów tworzonych z użyciem biblioteki mockującej?

No właśnie przez kontekst które fake'i dodają.

Dodaj sobie kontekst to mocków, to będziesz go miał.
Do fejków można też nie dodawać kontekstu, i będzie równie źle. Zwłaszcza, że te fejki to przecież normalne klasy, więc programiści mogą je zgwałcić na tyle różnych spaghetti sposobów, co i kod produkcyjny. W efekcie możesz mieć new MyFake(3, true, 6, false, [1, 5, 8], Mode.Default);
To nie jest problem narzędzia, tylko programisty. Jak ktoś jest ciamajda, to i fiuta w betoniarkę wkręci. Jeśli programista umie dodać kontekst w jednym przypadku, a nie umie w innym, to jest ciamajdą.

Jakbyś miał interfejs BankAccount, to co innego jest zobaczyć w teście fake'i:

Ale po co mieć taki interfejs? Implementacja łączy się z API banku?

0
somekind napisał(a):
rad1317 napisał(a):
TomRiddle napisał(a):

Tylko dlaczego utrzymanie wielu fake'ów ręcznie pisanych ma być łatwiejsze niż utrzymanie fake'ów tworzonych z użyciem biblioteki mockującej?

No właśnie przez kontekst które fake'i dodają.

Dodaj sobie kontekst to mocków, to będziesz go miał.
Do fejków można też nie dodawać kontekstu, i będzie równie źle.

No tak. Oczywiście że też będzie źle :|

0
somekind napisał(a):
rad1317 napisał(a):

Niby są przypadki, gdzie integrujemy się z zewnętrznymi systemami i tam mogło by to zdać egzamin, ale zazwyczaj są lepsze rozwiązania, jakieś testcontainers, mockwebserver itd.

Możesz pokazać jak przy użyciu tych narzędzi mockować SDK zapisujące do KV albo tworzące mikroserwis, wstawić dane do bazy albo odpalić przez API jakiś CI pipeline? (Tylko pamiętaj, że jak robię task biznesowy, to po prostu wywołuję metodę z jakimiś danymi, ja nie chcę nawet wiedzieć jak wygląda interakcja z tym API.)

Ale w czym problem żeby postawić to KV store lokalnie i w konfiguracji testowej podawać na nie namiary? To samo z bazą danych. Dodatkowo mozna na koniec calla zrobic do tych lokalnych instancji zeby sprawdzić czy faktycznie cos tam jest.
Natomiast faktycznie z zewnętrznymi serwisami typu CI / <wiele serwisów AWS> jest problem, sam chyba bym po prostu mockował w takich przypadkach. Ogolnie 'devopsowe' integracje są wyzwaniem przy testowaniu.

1

W końcu jaki jest wniosek jeśli chodzi o testowanie side effectów ? ;p

Czyli np publikowanie eventów albo wysyła maili?

Ja robiłem fejkowe implementacje interfejsów, które zapisywały sobie do wewnętrznych kolekcji i potem sprawdzałem bokiem stan. Bo to czy mi wyśle maila czy opublikuje event to i tak w 100% nie sprawdzę, bo to zewnętrzne systemy :D

Nie znam lepszych sposobów.

Ewentualnie jakieś testowe consumery rabitowe/kafkowe, które wepnę w testy integracyjne i sprawdzę czy nasłuchały eventu.

1
TomRiddle napisał(a):

No tak. Oczywiście że też będzie źle :|

A więc uznajemy, że ta antymockowa propaganda nie ma żadnych podstaw, bo każdy użyty argument uderza w nią samą?

Fedaykin napisał(a):

Ale w czym problem żeby postawić to KV store lokalnie i w konfiguracji testowej podawać na nie namiary?

Masz na myśli chmurę on-premise czy jakiś emulator? Jeśli pierwsze, to ile to kosztuje? Jeśli to drugie, to jaki emulator polecasz, żeby dał mi gwarancję kompatybilności z wersją KV, która jest używana na produkcji.
Gdy już rozwikłamy te zagadki, to pozostanie jedynie skonfigurowanie tego czegoś razy ilość osób w zespole.
Po co dokładać sobie roboty w jakikolwiek sposób choćby w szukaniu sposobu na zrobienie tego, skoro mocka mogę ogarnąć w nieskończenie mniejszym czasie?

To samo z bazą danych. Dodatkowo mozna na koniec calla zrobic do tych lokalnych instancji zeby sprawdzić czy faktycznie cos tam jest.

Tak, to zrobię w testach integracyjnych albo manualnych. Na późniejszym etapie pracy.

Natomiast faktycznie z zewnętrznymi serwisami typu CI / <wiele serwisów AWS> jest problem, sam chyba bym po prostu mockował w takich przypadkach. Ogolnie 'devopsowe' integracje są wyzwaniem przy testowaniu.

Nie, nie są, trzeba tylko wiedzieć, czy jest jakieś SDK, czy trzeba napisać samemu interakcję po jakimś API. Wówczas już wiadomo co mockować, a testy dalej pisze się banalnie.

Ogólnie polecam (wszystkim, to nie do Ciebie personalnie uwaga), aby nie siedzieć całe życie w projektach jednego rodzaju na bazie jednego frameworka i zobaczyć jak bardzo różne rodzaje softu wymagają różnych sposobów testowania, i jak bardzo różne podejścia trzeba czasem mieć nawet wewnątrz jednego projektu.

Też widziałem spaghetti-testy, które betonowały implementację z testami, ale to wynikało po pierwsze z chorego podejścia, że każda klasa musi mieć interfejs, a skoro jest interfejs, to go trzeba mockować, a po drugie z istnienia ogromnych god-objectów pełnych spaghetti i dziesiątek zależności. (Takie coś powstaje, gdy się nie ogarnia wzorców projektowych.)
Robienie czegoś tam, to było zakrzywianie czasoprzestrzeni, bo nie wiadomo ani gdzie zacząć, ani kiedy skończyć. No, ale to nadal nie była wina mocków, że ktoś najpierw skopał desing, a potem ich użył niezgodnie z przeznaczeniem w 100 razy więcej miejscach niż były rzeczywiście przydatne.

Bambo napisał(a):

W końcu jaki jest wniosek jeśli chodzi o testowanie side effectów ? ;p

Czyli np publikowanie eventów albo wysyła maili?

Chyba taki, że nie powinieneś ich testować, bo nie powinieneś ich mieć i prawidziwi pogramiści™ ich nie maja. A w ogóle to #walićbiznes #tylkonajnowszebuzzwordy i #najpierwarchitekturapotemwymagania. Jeśli biznes chce, żeby wysyłać maile, to mu wyjaśnij, że to jest nieprawidłowe technicznie, bo to side effect, a poza tym nikt nie czyta teraz maili, lepiej wrzucić na insta albo od razu na tiktoka.

1 użytkowników online, w tym zalogowanych: 0, gości: 1