Testowanie kontrolerów przy użyciu klienta http zamiast mock mvc.

0

Cześć, już kilka razy kilka osób tu na forum (szczególnie @Shalom) pisali o tym, żeby testować kontolery http za pomocą normalnego uderzenia do naszego serwera niż używania mock mvc.
Argumenty (z którymi się zresztą zgadzam i sam zacząłem tak testować):

  • robimy realne uderzenie nie pomijając niczego w przeciwieństwie do mock mvc, która omija trochę warstw tego połączenia
  • kod niższego poziomu mamy zamknięty w naszym cliencie
  • sam test jest mega zwięzły i zachęca programistę do napisania większej ilości tych testów, bo jest po prostu łatwo (nie ma tych wszystkich linijek z mock mvc, które musimy pisać za każdym razem)

Ostatnio jednak miałem ciekawą rozmowę z kolegami z pracy, którzy nadal wolą mock mvc, ponieważ testuje on realnego jsona, który jest zwracany na frontend (w przypadku kiedy nasz endpoint jest wystawiany dla frontu, a nie jako komunikacja z innymi mikroserwisami). Jeśli np zmienimy nazwę pola w wyjściowym dto z endpointu to nasze testy z wykorzystaniem napisanego klienta http nadal przejdą, jeśli użyliśmy opcji refactor name w Intellij, a na froncie już będzie problem. Podobnie jeśli mamy jakieś serializatory daty np - tu podobnie jest problem w takich przypadkach. Test nadal tego nie wykryje. Tu mock mvc ma taki plus, że faktycznie on sprawdza po prostu tego jsona i to wykryje.

Mój pomysł wstępnie był taki, żeby tego mock mvc zatrudnić do 1 testu sprawdzającego serializację, ale wtedy np logikę biznesową możemy już sprawdzać wstrzykując do testu bean z serwisem albo nawet bean z kontrolerem i w wyniku tego w ogóle nie potrzebujemy jednak tego clienta pisać.

I w sumie też nie do końca potrafię znaleźć kontretne, realne przypadki gdzie uderzenie do naszego serwera normalnie przez http clienta zamiast przez mock mvc sprawdzi nam coś czego nie sprawdzi mock mvc. Gdzie jest ta magia mock mvc, która może zakłamać nam testy?

3

@Bambo: ale kto komuś broni zamiast porządnym klientem stuknąć gołym klientem http i odczytać sobie wynikowego jsona? Bo chyba nie bardzo rozumiem problem. Gdzie tu jest jakaś zaleta mockmvc? Zamieniasz tą jedną linijkę kodu na inną, która uderza klientem http.
Zresztą to w ogóle jakiś argument z d**y, bo taki test nijak nie chroni przed tym że frontend ma inne pola :D Od tego są testy e2e żeby testować jak się ze sobą spinają elementy systemu (np. backend i frontend). Testy integracyjne na poziomie jednego serwisu nie sprawdzają czy inne serwisy dobrze z niego korzystają, bo nie od tego są.

Ad ostatniego pytania: https://www.baeldung.com/integration-testing-in-spring#mockmvc-limitations

tl;dr: nie testujesz aplikacji w taki sposób w jaki ona faktycznie ma działać, nie wysyłasz do niej prawdziwych requestów http, nie stawiasz servletów w taki sposób w jaki działają potem na produkcji.

ale wtedy np logikę biznesową możemy już sprawdzać wstrzykując do testu bean z serwisem

No możemy. Tylko po co? :D Ja lubie jednak testować aplikacje tak jak jest potem używana. Tzn odpalić ją, wysłać request, sprawdzić czy wynik jest ok. Bo wtedy mam pewność, ze to faktycznie działa. Jak sobie zrobisz test który uruchamia metodę jakiegośtam obiektu, to masz jedynie pewność że ta metoda działa, co dla mnie osobiście nie stanowi żadnego zapewnienia ze funkcja systemu w całości działa. Równie dobrze kontroler może przypadkiem wołać zupełnie inną metodę, albo coś się sypnie wcześniej i nawet do tej metody nie dojdziesz.
Jaki dokładnie masz zysk z takiego testu który pomija pół aplikacji? Tylko błagam nie pisz ze czasowy, bo pękne ze śmiechu.

z kolegami z pracy, którzy nadal wolą mock mvc

Znam takich. To są ci sami koledzy, którzy potem i tak odpalą sobie aplikacje i będą klikać ręcznie przed pushem na wszelki wypadek, albo będą odprawiać modły przed każdym deployem, bo nie wiadomo czy coś się nie wysypie.

0

@Shalom:
W sensie masz na myśli taki test, że uderzasz jakimś gołym clientem i nie parsujesz na dtosa tylko dostajesz gołego JSONA i założmy tworzysz sobie jakiś plik response.json i porównujesz czy są równe?

No nie chroni przed tym, że frontend ma inne pola ale chroni przed tym, że ktoś przez przypadek zmieni nazwę pola albo inne formatowanie takiego LocalDateTime no nie ? ;p
Dodatkowo w tym movkMvc sprawdzasz sobie pole po polu i test Ci zwróci, które pole w jsonie konkretnie jest do d ...
Generalnie staram się być adwokatem diabła :D

I co do tego, że chodzi mi o czas testów - nie. Wiem, że mockMvc pomija większość i w ogóle nie zapewnia realnego seciowego połączenia, ale właśnie ciekawią mnie konkretne przypadki, jakieś false positivy takiego testu :D Bo to, że on sobie mockuje requesty http i responsy to brzmi mocno, ale tak naprawdę jakie są tego realne i konkretne skutki. Po prostu nie potrafię wyobrazić sobie takiego przypadku.

I zaznaczam - bardziej podoba mi się rozwiązaniem z http clientem i rozumiem Twoje argumenty, ale potrzebuję rozwiać wątpliwości, które się pojawiły ;p

A co do testów e2e - nie mamy takich w ogóle :<

0

W sensie masz na myśli taki test, że uderzasz jakimś gołym clientem i nie parsujesz na dtosa tylko dostajesz gołego JSONA i założmy tworzysz sobie jakiś plik response.json i porównujesz czy są równe?

No jeśli ktoś uważa że taki test jest dla niego wartościowy, to nikt nie zabrania ci tak zrobić. Ja osobiście wole się skupić na testowaniu biznesowych funkcji systemu, a takie duperele zostawić na e2e bo wyjdą tam momentalnie już w pierwszym teście bo sie frontend nie zepnie z backendem.

Bo to, że on sobie mockuje requesty http i responsy to brzmi mocno, ale tak naprawdę jakie są tego realne i konkretne skutki. Po prostu nie potrafię wyobrazić sobie takiego przypadku.

Na przykład takie, że wiele błędów konfiguracyjnych w ogóle w takim teście nie wyjdzie (np. złe headery, źle ustawione spring security, np. http2.0 / http1.0 które może być nie wspierane, wszelkie dodatki w stylu filtry http w ogóle nie będą triggerowane), a jednocześnie zysk jest żaden. Co więcej takie cyrki sprzyjają pomysłom, żeby robić gdzieś jakieś @MockBean albo wstrzykiwać do testu jakieś obiekty z kontekstu springa, zamiast testować aplikacje ładnym blackboxem z punktu widzenia użytkownika.

I tak jak pisałem wyżej, ja generalnie raczej skupiam się na testowaniu biznesowych funkcji systemu i najlepiej testując je dokładnie w taki sposób w jaki aplikacja będzie używana. To na dobrą sprawę bez znaczenia czy jakiś konkretny problem mógłby u mnie w projekcie wyjść gdybym uderzał http clientem a nie wyszedł bo użyłem mockmvc. Dla mnie istotne jest, ze robie co innego niż w rzeczywistości i to jest wystarczający problem. Im bardziej skomplikowana technologia, tym więcej "dziwnych" rzeczy może się dziać po drodze, o których nie mam pojęcia, dlatego wole mieć testy które symulują prawdziwe wykonanie.

Zresztą jak napiszesz sensownego klienta i sensowny DSL do testów to potem wyglądają tak: https://github.com/Pharisaeus/almost-s3/blob/master/test/src/test/java/net/forprogrammers/almosts3/test/DownloadTest.java#L18 i nagle okazuje się że można testy pisać całkiem wygodnie i jednocześnie można mieć pewność, że jak są zielone to aplikacja faktycznie działa :)

A co do testów e2e - nie mamy takich w ogóle :<

Czekaj, czekaj, nie macie e2e a zamiast strzelać po http przynajmniej w testach integracyjnych to wolicie mockmvc? :D To teraz przyznaj się ile klikacie ręcznie po aplikacji przed każdym deployem...

2

Ponieważ, przeważnie nie korzystam ze Spring, a przynajmniej nie z magii springa to dla mnie fejkowe testy http sa sprawą jak najbardziej normalną i nie widze problemu.
Dzięki temu moge odpalić rownolegle wiele testów na wielu modułach bez obawy o "Port already in use". Robię to często w Ktor.
Serializacja jest w ten sposób sprawdzana, błedy wychodzą.
Nagłówki sa sprawdzane - błedy wychodzą.
I nie, testuje aplikacji po wrzuceniu - zapomniałem jak sie to robi. W niektórych aplikacjach faktycznie mam też testy (kilka) przez http - np. z e2e w półaczeniu selenium, ale po prawdzie nie kojarze ani jednego przypadku, żeby coś nie wyszło przez to, że było fejkowe http.
Ale tu podkreślam - zwykle nie korzystam z magii springa.

Mam też projekt w springu z mockmvc i też te testy działają - np. wykrywają problemy w serializacji.

0

Czyli @jarekr000000 o dziwo nie jesteś przeciwnikiem fejkowym testów http? Czego zatem używasz do tego poza poza mock mvc? Nie boli Cię to, że nie robisz realnego zapytania http?

@Shalom Tak, u nas klika się nawet miesiąc apkę przed wdrożeniem :D

1

Dla mnie to nie są tak do końca fejkowe testy. Po prostu chodzą na innym stosie. To tylko nieco gorzej niż testy przeprowadzone na sprzęcie z inną karta sieciową/albo konfiguracją sieci. Normalnie ludzie nie uznają tego za problem.
Jak długo te testy czasem coś pokazują (czyli czasem się wywalają) i nie widzę testów, które wywalają się na real http - to nie widze problemu.
Ale tu ciągle pozostaje uwaga, ja w sumie nie tak często springuje, a jak springuje to nie traktuje takich aplikacji poważnie. Jak ktoś ma Springa to chyba nie po to, żeby były sensowne testy, tam i tak wszystko się zawsze na produkcji łatwo może wyrypać.

0

@jarekr000000:
Ale to czego używasz do tych fejkowych testów?

2

najwiecej ostatnio to https://ktor.io/docs/testing.html
ale jak nie używasz Ktora to Ci się nie przyda

W Springu używałem MockMVC i WebTestClient - ten drugi jest nawet fajny - działa dobrze z WebFlux.

0

Ja zwykle pisałem testy używając klienta HTTP (RestTemplate), ale serializując wynik do HashMapy. Używając DTO z kodu produkcyjnego można zgubić takie tematy jak konwersja BigDecimali czy daty - test przechodzi, ale z API zwracamy inny format niż się umawialiśmy z naszymi klientami. Stosując prymitywną mapę i robiąc asercje na stringach wykryjemy takie problemy.

1

Z tym że fejk http nie przeszkadza w testowaniu gołego responsa. Jako nawet strumień bajtów, z nagłowkami itp. Bywa, że faktycznie sprawdzam po prostu czy response zgadza się z oczekiwanym stringiem. Przyznaje, że najczęściej z lenistwa.

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