Wstrzykiwanie rzeczywistych DAO do testów w Springu

0

Cześć, piszę Api Restowe w Spring Boot i chciałbym je przetestować. Na tym forum spotkałem się już z kilkoma szkołami, gdzie np. testujemy każdą linijkę kodu lub gdzie testujemy tylko warstwę logiki biznesowej. W moim projekcie zamiast warstwy serwisów zrobiłem sobie tak jak poleca Uncle Bob warstwę UseCasów - gdzie każdy z nich odpowiada określonemu zadaniu w aplikacji i nie łamie zasady pojedynczej odpowiedzialności, np. GetUsers, AddPost, PrintRaport .. itd. Każdy z tych obiektów posiada własny obiekt zapytania, który jest oczywiście tworzony w kontrolerze na podstawie parametrów zapytania. Wszystko fajnie działa, usecasy nie są przerośnięte jak serwisy i ok.

I teraz tak, chciałbym testować każdy z tych usecasów. Wpadłem na pomysł, że będę wstrzykiwał realne obiekty DAO ( rozszerzane JpaRepository ) i dla testu będę podmieniał za pomocą @ActiveProfiles bazę danych na testową, napiszę sobie jakiś filler do bazy danych tak, żebym mógł sprawdzać te use casy na realnych rzeczach w bazie. Niestety nie mogę wstrzyknąć nic do tego testu przez autowired. Tzn mogę, ale tam nulle są.

Pytanie do Was po pierwsze takie, jak mogę wstrzyknąć coś do testu, a druga sprawa czy mój pomysł na testowanie jest dobry. Bo np będę chciał sobie wytestować AddPost, no to muszę dodać realnie do bazy danych obiekt i potem sprawdzić czy to co dodano jest tym samym co chciałem żeby dodano.

Pozdrawiam

0

Jest to pomysł słaby bo to nie jest już test jednostkowy i jest to overkill. Zrób testy jednostkowe logiki i testy integracyjne endpointów :)

0

Czyli mokować DAO wstrzykiwane do tych usecasow ? Ale to jest też tak przecież, że poprawność usecasa zależy od tego czy dobrze jest napisane customowe query .. i jak mam zmokować takie query to się robi trochę bez sensu no nie ?

1

To testujesz w testach integracyjnych z jakąś bazą w pamięci najlepiej tą, której używasz na produkcji, ale resztę rzeczy testujesz jednostkowo tak jak scibi zalecił i wtedy możesz je mockować.

1

Jeśli twój projekt jest bazo/sql centryczny - czyli wszystkie dane pochodzą z bazy. To jeśli nie tesujesz tego z bazą to zachodzi pytane co właściwie testujesz?

Ja nawet nie uważam tego za test integracyjny. Jak to jest trywialne DAO, a baza danych jest moja (założona przeze mnie na potrzeby tego projektu) - to taką baze traktuję jako kawałek implementacji klasy (DAO).

Ja robię takie testy przez normalne wstawianie "dao" do serwisu. Dao chodzi na in memory database (np HSQLDB).

(btw. mam nawet taki jeden projekt Springowy i jakoś nie mam tam nulli - się wstrzykują.
Żeby zobaczyć czemu u Ciebie nie , trzeba by źródła z całym buildem).

Normalnie jakkolwiek sobie tego nie robię i zwyczajnie obiekty przez new instancjonuje.
Wtedy nie mam nulli - profit. Nie mam beanów, nie mam raka - profit.

0

Dla mnie to jest normalna praktyka testować integracyjnie API restowe czy inne moduły. Jest to coś co wymaga dużego nakładu pracy, aby stworzyć właściwą konfigurację na potrzeby testów integracyjnych. W Springu jest to stosunkowo przyjemne. Nie każdy student to potrafi.

Ogólnie najczęściej używa się:

  • embedded bazy danych (lub biblioteki, która ją symuluje przy użyciu prawdziwej bazy danych), trzeba zapewnić odpowiedni stan przed uruchomieniem każdego testu (w zasadzie sam pracuje teraz nad takim rozwiązaniem dla PostgreSQL, oczywiście nie chce używać HSQL, H2: raczej idę w stronę prawdziwego PostgreSQL i biblioteczki symulującej embedded bazę)
  • przed każdym testem trzeba np. odtworzyć odpowiedni schemat bazy w przypadku baz relacyjnych: stworzenie danych do warunków początkowych testu może być bardzo kosztowne i bardziej nietrywialne niż klepnięcie samego testowanego kodu (znacznie większy wysiłek)

Mockowanie DAO spotyka się w testach jednostkowych, ale to trochę inna kategoria testów. Służą bardziej do wykrycia grubych fuckupów zanim zacznie się odpalać właściwe testy integracyjne oraz testowania modułów, gdzie pisanie ciężkich testów integracyjnych nie ma sensu np. różne dziwne warunki brzegowe.

Generalnie i tak lubię mieć test jednostkowy na każdy if, bo ich pisanie jest szybkie i tanie, ale ciężko się pracuje bez kilku dobrych testów integracyjnych.

0

@Bambo: nie, poprawnośc klasy nie zalezy od tego. Od tego jest na przykład Mockito, a Ty testujesz Twoją klasę. Zresztą DAO to zazwyczaj trywialne obiekty zwłaszcza w Sprigu Data

2

Trywialne DAO na SpringData - rzeczywiście nie ma po co specjalnie testować. Takie DAO jest też dobrym wyznacznikiem, że ktoś użył bazy danych SQL w projekcie, który tej bazy nie potrzebował :-). W IT normalka.

0
jarekr000000 napisał(a):

Jeśli twój projekt jest bazo/sql centryczny - czyli wszystkie dane pochodzą z bazy. To jeśli nie tesujesz tego z bazą to zachodzi pytane co właściwie testujesz?

Ja nawet nie uważam tego za test integracyjny. Jak to jest trywialne DAO, a baza danych jest moja (założona przeze mnie na potrzeby tego projektu) - to taką baze traktuję jako kawałek implementacji klasy (DAO).

Ja robię takie testy przez normalne wstawianie "dao" do serwisu. Dao chodzi na in memory database (np HSQLDB).

HSQLDB wstaje przy rozpoczęciu testów i umiera na ich koniec. Rozumiem masz do tego przygotowane schematy i ewentualne podstawowe dane które za każdym razem są odpalane.

  • Czy nie ma problemów database-specific? Np. na produkcji lata MS SQL SERVER i mamy hand-crafted SQLe.
  • Czy testy nie zamulają? Uruchamianie takiej bazy trwa (zresztą, ten sam problem przy stawianiu Springa do testów). Czy to nie zaczyna męczyć?
3

Dawno nie miałem MS SQL - normalnie mam ORACLE (produkcja) , MySQL lokalna developerka (czasem). H2SQL lub HSQLDB in memory na testy.
Reczne SQLe nawet te porypane z CASE, group by przechodzą. Są wyjątki - wtedy sa testowane klasycznie "integracyjnie" przez odpalanie z prawdziwą bazą (ale zawsze są z tym problemy) wiec unikamy.
Wkurzające jest raczej utrzymywanie trzech rozłącznych i niepodobnych DDL (mam już któryś projekt gdzie sie rozjechały ... ).

Zamulanie nie - H2SQL było tak szybkie, że nawet miałem w paru projekach odpalanie bazy per każdy test ( a nie dla TestSuite albo dla wszystkich testów w projekcie). (ale ten szybki to był projekt bez Springa - nie miało co zamulać).
Na in memory testuję na minimalnej ilości danych - podane jest pare insertów na tebelke i sprawdzamy czy wyniki się zgadzaja. To musi być łatwe do ogarnięcia i refaktoringu.

Kiedyś bawilem sie w wiele patentów typu automatyczny rollback po teście - coby bazy danych nie inicjalizować od nowa za każdym razem.
Teraz to olewam - na ogół nie ma problemu z szybkością takich testów.

1

Jednak jak robię coś po stronie bazy to chciałbym mieć dostęp do jej power-featerów jak np. funkcje agregujące, prawdopodobnie poza standardem SQL. Więc użycie embedded bazy odpada. Również czasem jak trzeba coś szybko zrobić (nie zawsze da się używać jednego query) to przydają się procedury (znowu kontrowersyjny temat, bo ciężko się to testuje: ale co zrobić jak nie chce się przesyłać danych w jedną i drugą stronę między aplikacją, a RDBMS). Dotyczy to aplikacji mocno zorientowanych na dane silnie powiązanych z jednym konkretnym silnikiem. Dlatego chcę mieć rozwiązanie, które zadziała z prawdziwą bazą.

W sumie jestem pod wrażeniem generalnie możliwości PostgreSQL. Może to trochę niebezpieczna fascynacja, bo 95% aplikacji nie potrzebuje skomplikowanego narzędzia raportującego i do analizy danych.

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