Jak mogę używać testów jednostkowych i TDD do testowania aplikacji, która opiera się głównie na operacjach CRUD bazy danych?

22

W pracy jeden z moich projektów polega głównie na pobieraniu danych przekazywanych od klienta zewnętrznego i utrwalaniu ich w bazie danych. Jest to aplikacja Java dla przedsiębiorstw korzystająca z JPA i większość naszej logiki dotyczy operacji CRUD.

Większość naszych błędów dotyczy JPA w taki czy inny sposób.

  • Przykład 1: Jeśli klikniesz przycisk Zapisz dwa razy, JPA może spróbować wstawić ten sam byt do bazy danych po raz drugi, powodując naruszenie klucza podstawowego.
  • Przykład 2: pobierasz jednostkę z bazy danych, edytujesz ją i próbujesz zaktualizować jej dane. JPA może próbować utworzyć nową instancję zamiast aktualizować starą.

Często rozwiązanie wymaga dodania / usunięcia / zmiany adnotacji JPA. Innym razem ma to związek z modyfikacją logiki DAO.

Nie mogę wymyślić, jak uzyskać zaufanie do naszego kodu za pomocą testów jednostkowych i TDD. Nie jestem pewien, czy to dlatego, że testy jednostkowe i TDD są źle dopasowane, czy też źle podchodzę do problemu.

Testy jednostkowe wydają się źle dopasowane, ponieważ mogę wykryć te problemy tylko w czasie wykonywania i muszę wdrożyć na serwerze aplikacji, aby odtworzyć problemy. Zwykle baza danych musi być zaangażowana, co uważam za niezgodne z definicją testu jednostkowego: są to testy integracyjne.

TDD wydaje się źle dopasowane, ponieważ pętla testowa wdrażania + testowania jest tak wolna, że ​​czyni mnie bardzo nieproduktywnym. Pętla opinii wdrożeniowych + testowych zajmuje ponad 3 minuty, i to tylko wtedy, gdy przeprowadzam testy specjalnie na temat kodu, który piszę. Uruchomienie wszystkich testów integracyjnych zajmuje ponad 30 minut.

Poza tą formą jest kod i zawsze testuję to urządzenie, kiedy tylko mogę. Ale większość naszych błędów i największe pochłanianie czasu zawsze dotyczy JPA lub bazy danych.


Jest inne pytanie, które jest podobne , ale jeśli zastosuję się do porady, skończę z najbardziej niestabilną częścią mojego kodu (JPA) i przetestuję wszystko oprócz tego. W kontekście mojego pytania byłbym w tej samej złej sytuacji. Jaki jest następny krok po pakowaniu JPA? IMO to pytanie jest (być może) krokiem do odpowiedzi na moje pytanie, ale nie jest odpowiedzią na to pytanie.

Daniel Kaplan
źródło
4
To, co robisz, to zasadniczo test integracyjny, ponieważ musisz skonfigurować bazę danych do testowania. Mogę sobie wyobrazić, że jeden moduł będzie polegał na innych, więc uczyń go jeszcze bardziej jak test integracji. Chciałbym zmienić pytanie, jak zastosować podejścia TDD do swojej aplikacji.
Poinformowano
@ losowo Prawidłowo zredagowałem swoje pytanie, aby to wyraźnie powiedzieć. Nie rozumiem, dlaczego polecasz zmienić pytanie. Czy możesz rozwinąć? Chcę zachować część testów jednostkowych w tam, bo bym raczej pisać testy jednostkowe niż testów integracyjnych (choć jestem świadomy, że unit testing != TDD)
Daniel Kaplan
nic specjalnego, po prostu umieść tam TDD. Jeśli masz tam test jednostkowy, wiele osób uważa, że ​​nic nie rozumiesz itp. Nie jest to dla ciebie dobre.
InformedA

Odpowiedzi:

7

Jedną z opcji jest użycie testowej bazy danych w pamięci, takiej jak H2 ; jest on około 10 razy szybszy niż standardowa baza danych wykorzystująca dyski i przy krótszych czasach uruchamiania / rozłączania.

To, czy to pomoże, zależy w dużej mierze od tego, czy problemy JPA, które masz, są na tyle ogólne, że nadal będą zawieść w różnych bazach danych. Nie ma większego sensu przeprowadzanie testów szybciej, jeśli przeoczą większość problemów.

Ale jeśli możesz wykonać 10 przebiegów z H2 dla każdego z pełnym systemem, może się to opłacić.

soru
źródło
To miła myśl, ale nadal musiałbym wdrożyć na serwerze aplikacji, AFAIK. To dużo ponad 3 minut. To powiedziawszy, zdecydowanie warto to zrobić. Ale nadal trudno sobie wyobrazić przeprowadzanie testów tak często, jak uruchamiałbym testy jednostkowe i dlatego wydaje się nieefektywne przy użyciu TDD.
Daniel Kaplan
1
Myślę, że zwykle istnieje możliwość obejścia tego wymogu (np. Docs.oracle.com/middleware/1212/toplink/TLADG/testingjpa.htm ). Jednak dość duża szansa na więcej pracy niż uzasadniona; inną opcją byłoby zdobycie bardziej rozbudowanych serwerów testowych i równoległe uruchamianie.
soru
1
@tieTYT Mój własny dowód koncepcji z jednostką hsqldb testującą surową aplikację internetową na github: TestingWithHsqldb - testy jednostkowe nie wymagają wdrożenia aplikacji.
3

Bazy danych mogą być bardzo łatwe do testowania jednostkowego - potrzebujesz procedur przechowywanych i transakcji.

To, co Microsoft mówi o testowaniu jednostek bazy danych . Możesz także uruchamiać testy jednostkowe na bazie danych, pisać testy w Javie lub C #, konfigurując połączenie DB, rozpoczynając transakcję, zapisując w DB dowolne dane, których chcesz użyć do testu, uruchom testy, a następnie wycofaj. Bez uszkodzenia bazy danych, jeśli korzystasz z tej, do której również zostałeś wdrożony i otrzymujesz w pełni izolowane testy.

Mam nadzieję, że to da ci wgląd w to, jak to zrobić w swoich ramach.

gbjbaanb
źródło
Jak powiedziałem: „Większość naszych błędów wiąże się z JPA w taki czy inny sposób”. Myślę, że porady zawarte w tym artykule pominęłyby wszystkie z nich. Ponadto, jeśli uważasz te testy Java / C # za nadal testy jednostkowe, mamy bardzo różne definicje. Myślę, że jest to ogólnie dobra rada, ale nadal wydaje się, że wdrożenie i uruchomienie pakietu zajęłoby mnóstwo czasu, a zatem nie sprzyja TDD. Nie zgadzasz się
Daniel Kaplan
Kiedyś przeprowadzaliśmy testy jednostkowe DB dla naszego SQL, ale potem wszystkie były w sprocach. Chociaż można jednostka katalog testy sql z innych procedur SQL, nasz system testowania jednostka była MSTest tak to miało sens, aby uruchomić je stamtąd (hej, mamy zielone znaczniki na serwerze kompilacji, która była najważniejszym czynnikiem). Jeśli masz bazę danych zawsze aktywną (a zresztą zrobiliśmy to dla testów wewnętrznych), łatwo jest załadować cały kod SQL i uruchomić wszystkie testy jednostkowe na serwerze kompilacji. Czasami musisz być pragmatyczny w tych sprawach.
gbjbaanb
Nie sądzę, że odpowiedziałeś na moje pierwsze zdanie.
Daniel Kaplan
więc po prostu użyj jpa-unit. Nie mogę odpowiedzieć na pytanie, jak działa twój kod JPA (lub nie), po prostu spróbuj dać ci kilka pomysłów na przetestowanie tego sql w db.
gbjbaanb
3

Inne osoby odpowiedziały „Wyśmiewaj się z DB!” - ale po co kpić z warstwy DB, jeśli faktycznie trzeba przetestować jej interakcję z kodem?

To, czego szukasz, to testy integracyjne i / lub automatyczne testy interfejsu użytkownika. Wspomniałeś, że problem występuje, gdy:

*If you click the save button twice*

Jedynym sposobem na przetestowanie tego jest napisanie automatycznego testu interfejsu użytkownika w celu dwukrotnego kliknięcia przycisku. Może sprawdź Selenium.

Prawdopodobnie będziesz również potrzebował jednostki testującej DB i do swoich testów skieruj ją w tym kierunku. Ból w utrzymaniu, ale mile widziany TDD w prawdziwym świecie.

Rocklan
źródło
to brzmi bardziej jak rant niż odpowiedź
komnata
Odpowiedziałem na to pytanie trzy razy - testy integracji, testy GUI i / lub testowanie jednostki DB. Tak, to trochę rant, teraz zmienię to na pozór zdrowego rozsądku.
Rocklan
1
„Jedynym sposobem na przetestowanie tego jest napisanie automatycznego testu interfejsu użytkownika w celu dwukrotnego kliknięcia przycisku. Może sprawdź Selenium.” W takich sytuacjach backend lepiej zapobiega temu, w przeciwnym razie interfejs użytkownika miałby bezpośredni dostęp do bazy danych.
Daniel Kaplan
0

W przykładzie podanym w pytaniu nie można przeprowadzić testu jednostkowego / TDD w sytuacji dwukrotnego kliknięcia przycisku, aby bardzo łatwo spowodować błąd. Ale to, co możesz przetestować w jednostce, to kod w kodzie, który jest wywoływany po kliknięciu przycisku, jeśli otrzymasz wyjątek od warstwy trwałej, odpowiednio ją obsłużysz (albo wyśmiewając warstwę trwałą, albo używając bazy danych w pamięci jako zostało zasugerowane w innych odpowiedziach) - albo przez ponowne wyrzucenie, albo wyświetlenie błędu lub cokolwiek innego.

Masz rację, że TDD może zacząć się psuć, gdy musisz wykonać testy, które nie są odpowiednie dla testu jednostkowego (tj. Testy integracyjne / systemowe) - to stanowiło spory temat dyskusji w ostatnim „Is TDD” Nie żyje?" debaty między Kentem Beckiem, Martinem Fowlerem i Davidem Heinemeier Hanssonem: http://martinfowler.com/articles/is-tdd-dead/

Chris Cooper
źródło