Testy integracyjne - API czy serwisy?

0

Jaka jest przewaga testowania API webowego nad testowaniem serwisów warstwy aplikacji? Chodzi mi o:

  1. Client.Get("/api/users/1")
    vs
  2. UserModule.ExecuteCommandAsync(new GetUser(1)).

W podejściu 1 możemy przetestować, czy działa autoryzacja i walidacja, ale jeśli np. wykorzystujemy wzorzec mediator i pipeline'y, to walidację możemy też przetestować też w podejściu 2. Mam wrażenie, że przy podejściu 2 jest mniej magii. Widzę na githubie, że często ludzie robią albo (1), albo (2), a czy nie powinno się tych podejść łączyć?

Testy integracyjne (2) w https://github.com/kgrzybek/modular-monolith-with-ddd wyglądają na wiarygodne imo.

0

Po pierwsze, polecam Odwrócona piramida testów

Po drugie, to zależy, powiedzmy, że testujesz to pobieranie użytkownika. Jaką masz tutaj logikę do sprawdzenia? Jeżeli napiszesz test jednostkowy sprawdzający serwis, pomijając warstwę HTTP, a dodatkowo jeszcze zamockujesz bazę danych to tak naprawdę ten test nie ma najmniejszego sensu. Nawet jak ta baza nie będzie mockiem, tylko np. odpalisz prawdziwą bazę w testcontainers, to co z tego jak połowa rzeczy wartych przetestowania siedzi w warstwie controllera? Mowa o autentykacji, poprawności danych, spięcia infrastruktury z domeną, itp. Nawet jeżeli możesz to wszystko sprawdzić bez controllera, to jednak pomijasz test głównego punktu wejścia do aplikacji, co nie wydaje się rozsądne. Oczywiście, możesz testować jedno i drugie, ale jeżeli test controllera może pokryć cały use case, to po co testować ów funkcjonalność dwa razy?

Z drugiej strony, jeżeli to nie jest operacja typu GET, tylko np. DELETE który musi po drodze wykonać kilka obliczeń, czy walidacji nieco bardziej skomplikowanych niż email.isValid(), a dodatkowo musi uderzyć do kilku innych systemów, to wtedy jak najbardziej warto napisać bardziej granularne testy, które sprawdzą cały flow operacji.

0

Moim zdaniem to zależy. Pytanie od czego?

Kontrolery powinny być głupie. To znaczy powinny pytać o wszystko serwisy, tak żebyśmy w przyszłości mogli je zmieniać swobodnie. Czyli nie masz tam żadnej logiki, czyli nie ma sensu w sumie tego testować.

Natomiast w infrastrukturze mikroserwisowej warto napisać również testy integracyjne, najlepiej w postaci jakiegoś klienta, który będzie wysyłał różne rzeczy.

Np. masz kilka mikroserwisow, które będą odpytywac siebie nawzajem, token jwt będzie generowany na 3 sekundy z różnych atrybutów np identyfikatora sesji połączenia usera z systemem, jego hasła itd..
masz tutaj logikę, która porusza się poziomie oddzielnych mikro. Należy sprawdzić czy sygnał, który wyślemy zwróci nam to co chcemy.

Masz wtedy testy integracyjne ALE generowane z jakiegoś ZEWNETRZNEGO klienta.

Natomiast testy konkretnych usług serwisowych masz z WEWNĘTRZNEGO mikroserwisu.

W monolicie, jak nie chcesz testować jakiegoś tokena czy czegoś z http to kontroler powinien być głupi a ty powinieneś testować od serwisu.

3

czyli nie ma sensu w sumie tego testować.

xD No jasne, bo nie ma znaczenia np. auth albo parsowanie parametrów, albo czy zwracasz jsona czy jakieś binarne dane itd.

Moim zdaniem aplikacje należy testować tak jak jest używana, czyli od entry pointu. Jasne, możesz zejść poziom niżej i pominąć kawałek aplikacji, tylko czemu to niby ma służyć?

1

Kontrolery powinny być głupie. To znaczy powinny pytać o wszystko serwisy, tak żebyśmy w przyszłości mogli je zmieniać swobodnie. Czyli nie masz tam żadnej logiki, czyli nie ma sensu w sumie tego testować.

Z tym się akurat nie zgadzam, tzn. tak, controllery powinny być głupie, ale są jednak punktem wejścia do systemu. Nawet taki controller, który po prostu deleguje zadanie do serwisu, jest ważną rzeczą do przetestowania bo korzystając z większości frameworków webowych, taka autentykacja odbędzie się właśnie na tym poziomie (a w sumie jeszcze przed controllerem). Można się bronić argumentem, że takie testy contollerów są poniekąd zależne od frameworka czy infrastruktury, ale:

  • dużo częściej będzie się zmieniać implementacja domeny, która na bieżąco pewnie jest refaktorowana, itp. W sumie nie słyszałem jeszcze, by ktoś skorzystał na tym, że domena jest całkowicie oderwana i przetestowana w izolacji, co zaoowocowało tym że mógł Springa wymienić na Quarkusa. Duzo częściej za to zabetonowanie testów na poziomie serwisów powoduje koniecznośc ich zmiany z każdą zmianą implementacji.
  • testy integracyjne, poprzez endpoint aplikacji, nie są wcale zależne od frameworka czy języka. O ile nie korzysta się z frameworkowych narzędzi do testów, tylko stawia się klienta HTTP, to można tę Jave pod spodem wymienić na C# i pomijajc fakt, że testy mamy w dwóch różnych technologiach, wszystko powinno nadal działać.
1

dużo częściej będzie się zmieniać implementacja domeny, która na bieżąco pewnie jest refaktorowana

O to to! Całkiem niedawno robiłem takie mega zmiany w pewnej aplikacji, praktycznie przeorana logika domenowa, ale wszystko spoko właśnie dlatego ze były testy stukające przez całą aplikacje. Dzięki temu nie obchodzi cię że serwis X zniknął a serwis Y podzielił sie na 2 pozostałe, bo test sprawdza czy funkcja systemu działa a nie czy kod się czasem nie zmienił. O ile API jest takie jakie było i logika robi to co miała robić, to testy nadal powinny być zielone.

0

Przy używaniu mediatora problem dotyczący zmian implementacji serwisów wymuszających zmianę testow znika moim zdaniem, no bo usunięcie komendy będzie pewnie w większości równoważne z usunięciem całego endpointa, czyli wychodzi na to samo.

1

Robię 1 i 2. Na 1 wychodzi bardzo dużo nieoczywistych błędów. Mając do tego 2 szybciej można znaleźć miejsce błędu i przetestować więcej klas danych wejściowych, unikając robieniu tego na każdym endpoincie korzystającym z tego serwisu więc unikając duplikacji

0

Jeżeli nie miałbym testów typu 1, to by znaczyło, że sam muszę API uruchomić, powysyłać requesty i zobaczyć, co zwracają. Generalnie nie mam czasu na małpią robotę i wolę testy automatyczne.
A jak już mam automatyczne testy typu 1, to testy typu 2 nic nie wniosą, a ich pisanie będzie tylko stratą czasu.

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