Zasadność używania verify z Mockito

0

Cześć. Spotkałem się tutaj wiele razy ze zdaniem, że nie ma sensu testować za pomocą verify z mockito czy dana metoda się wywołała, ewentualnie ile razy.
Miałem rozmowę o pracę, gdzie rekruter mocno się upierał, że trzeba przetestować czy na pewno jakaś metoda wewnątrz testowanej metody się wywołała i to z odpowiednimi argumentami.

Do tej pory sam stosuję BDD i w sumie mam taką zagwozdkę:

Jeśli jakaś metoda serwisowa pobiera encje, wykonuje na niej jakąś logikę i z powrotem zapisuje do repo, a następnie zwraca encje po zapisaniu to ja do tej pory po prostu testowałem czy ta zwrócona encja ma oczekiwany stan. Ewentualnie lepiej można tą encję wyciągnąć z bazy za pomocą id i ją przetestować, ale jeśli się robi CQRSa to jest troszkę problem.

I w sumie takie testowanie BDD to jest trochę dawanie zaufania, że metoda w środku naprawdę wykonuje tego save do bazy, bo samo testowanie wyjścia metody nam tego nie sprawdzi przecież. Mogę w testach integracyjnych teoretycznie po wykonaniu takiej metody sprawdzić przez jakiś findById czy mi da zmofyfikowaną encję, ale co w przypadku, kiedy moje webowe api nie odostępnia metody szukania danej encji po id ? Czy w tym wypadku zostaje naprawdę Mockito.verify na poziomie testów jednostkowych czy po prostu ufamy na ślepo, że metoda jednak zapisuje coś do bazy ?

1

Zauważ, że mockujesz głównie dlatego, że stawianie świeżej bazki dla każdego testu jest kosztowne. Jedynym słusznym rozwiązaniem jest więc:

  • wywalenie Mockito w niebyt, a potem
  • napisanie testowego DAO operującego na kolekcjach
  • testy do obu DAO (czyli zarówno testowego DAO operującego na kolekcjach jak i produkcyjnego DAO operującego na bazie) powinny być te same
  • jest to trywialne do osiągnięcia jeśli testowe DAO dziedziczy po produkcyjnym DAO i nadpisuje wszystkie metody
  • nie sprawdzałem czy to podejście jest kompatybilne z ORM (czy tam ORMO albo inne ZOMO) ale w przypadku połączenia z http://slick.lightbend.com/ sprawdza się znakomicie
  • pomysł zaimplementowałem już w jednym mikroserwisie w firmie
  • porównanie Slicka i ORMa: http://slick.lightbend.com/doc/3.2.3/orm-to-slick.html
  • Slick jest porównywalny z jOOQ: https://www.jooq.org/
  • z tego co widzę nie da się uruchomić Hibernate bez żadnej bazy SQLowej pod spodem
    • gdyby Hibernate miał wbudowany tryb operowania na kolekcjach zamiast na SQLowej bazie to problem stałby się trywialny

Disclaimer:
Jestem Scalowcem od paru lat :]

0

@Wibowit:

Na czas testów mam in memory dao operujące na hashmapach. Po prostu mam architekturę CQRSa i daoCommand i daoQuery nie wiedzą o sobie - operują na niezależnych HashMapach i nie mam jak sprawdzić czy jeśli wrzucę coś do daoCommand to czy faktycznie ono tam jest bo daoQuery nic o tym nie wie - testy command i query mam niezależne.

1

W sumie to CQRSem się nie zajmowałem, ale

testy command i query mam niezależne

czy nie wartałoby zrobić połączenia między testowymi DAO oraz zrobić testów weryfikujących współpracę command-side i query-side? Nie wiem jaką masz architekturę, ale takie połączenie testowych DAO (bo połączenie produkcyjnych i tak musi być mniej lub bardziej pośrednio) i testy takiego połączenia (zarówno testowych jak i produkcyjnych DAO) mogłyby być sensowne (jednak zaznaczę jeszcze raz że doświadczenie z CQRSem mam zerowe). Odpada wtedy przynajmniej filozofowanie z mockami i konieczność ich aktualizacji w przypadku zmian w kontrakcie (w tych samych momentach w których zachodziłaby konieczność aktualizacji potencjalnej dokumentacji).

1

@Wibowit:
Dzięki.
Utworzyłem sobie taką konfigurację, że cała apka na czas testów chodzi na bazach utworzonych na mapach z vavra. Każdy z pakietów ma swój moduł do konfiguracji, mam klasę InMemoryAppModule, tam te moduły ze sobą łączę i na testach nie muszę podnosić springa.

2

Miałem rozmowę o pracę, gdzie rekruter mocno się upierał, że trzeba przetestować czy na pewno jakaś metoda wewnątrz testowanej metody się wywołała i to z odpowiednimi argumentami.

To jest rak whitebox testingu, który cementuje testy. Bo co taki test sprawdza? Nie czy kod jest poprawny (do tego wystarczy sprawdzić czy daje dobre wyniki). To sprawdza czy kod wygląda tak samo jak wyglądał kiedy pisano test! A co jak zrefaktorujesz wewnętrzne api i nagle będziesz wołał tą logikę przez jakieś proxy? Twój test się wywali, bo wołasz coś nie na tym mocku co trzeba...

Używanie verify powinno być stosowane tylko do bardzo szczególnych sytuacji, kiedy faktycznie musimy jakiś side-effect sprawdzić. Np. testujesz cache i chcesz zeby raz wartość pobrała się z repozytorium a kolejny raz już z cache. Możesz do tego użyć właśnie verify. Ale jak już wchodzisz na etap testowania kolejności wywołań, albo krotności to znaczy że coś jest bardzo nie tak.

2

Rakiem testowania jest nałogowe mockowanie warstwy bazodanowej bez chociażby jednej próby stworzenia InMemoryDao :]

2

Mocksturbation

0

A co sądzicie na temat testowania kontrolerów w Springu przy pomocy Mockito? Dla "endpointów" GET jakoś idzie (każda książka, każdy kurs o tym uczy) ale krew mnie zalewa przy PUT gdy próbuję zrobić mocka serwisu który wywołuje metodę, która gdzieś tam pod spodem robi update pola poprzez przypisanie nowej wartości enum. Niby prosty test, który ma sprawdzić czy wywoła się metoda robiąca update pola w db.

0

Testy endpointowe najlepiej zrobić bez mocków (chyba że są zewnętrzne zależności, np. masz serwis strzelejący do githuba to wtedy to wypada zamockować) i jak masz baze danych to zrobić ja w pamieci (np. H2)

0

@scibi92:

A testy endpointowe nie lepiej traktować jako akceptacyjne i zamiast mockować zewnętrzne serwisy i stawiać h2 to uderzyć pod realny url do tego githuba i tej samej bazy co prod - w sensie silnika ? W końcu tu chcemy testować realną apkę, więc sprawdźmy ją na tej samej konfiguracji co prod. Jak github padnie i testy siądą to wiemy, że produkcja też nie zadziała.

Te testy mowią nam czy robimy hajs, więc imho warto je uruchamiać przed samą wgrywką na proda na żywym organiźmie gdzie testujemy tylko główny flow bez corner casów. Te testy puszczasz rzadko i one też trwają kilkadziesiąt sekund .. a już szczegółowe testy z corner case'ami na poziomie modułów pisać jednostkowo - z i/o w pamięci - uruchamiają się kilka s.

0

Ale ja miałem na myśli testy przeprowadzone przez programistów a nie testy tzw blackboxowe przeprowadzane przez testerów

0

@scibi92:
Ale dlaczego uważasz, że ja pisałem o testach blackboxowych ?

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