Z drugiej strony to ze takie testy są czerwone znów niczego mi nie mówi, bo takie testy maja tedencje do failowania przy dowolnym refaktoringu i znów to że są czerwone mówi ci tylko że jakiś kawałek kodu nie działa zgodnie z asercjami w teście (a często są czerwone tylko dlatego że struktura kodu się zmieniła, nagle wołamy metodę X a nie Y i mocki się zesrały).
Czyli w sumie nic mi te testy nie mówią o stanie systemu. Tylko co najwyżej o jakimś kawałku kodu.
Tylko jeśli jesteś na tyle nieodpowiedzialny żeby napisać testy które są tightly-coupled do kodu, że failują z takich randomowych powodów. Twój argument (ten konkretny) to nie jest argument przeciwko pisaniu testów które się odpala bez stawiania aplikacji, tylko przeciwko pisaniu testów które są przywiązane do implementacji. I ja się zgadzam.
Ja rozumiem, że łatwiej jest sobie powiedzieć "To nie moja wina że test sfailował, to wina tego że odpalamy testy na kodzie zamiast na aplikacji". Taka strefa komfortu. Ciężko jest się przyznać przed sobą "napisałem słaby test". Więc łatwiej jest zrzucić na runner testów, albo na proces, albo czasem na bibliotekę. Ale again, w dobrze napisanym test suitecie nie ma miejsca na coś takiego. Gdyby mi sfailował test przez refaktor - to nie powiedziałbym "aaag, muszę odpalić testy na prawdziwej aplikacji" tylko powiedziałbym "ten kto napisał ten test zjeb***" (i w 99% przypadków to byłbym ja sam). Nie każdy jednak ma zdolność do tego. Łatwiej jest się wyprzeć i zrobić talki walk around.
Także zgadzam się. Testom które failują randomowo przy rafaktorze nie można ufać. Ale radą na to nie jest odpalanie testów przy stojącej aplikacji, tylko konsekwentna poprawa dyscypliny w pisaniu dobrych testów. Ale zmiana w sobie wymaga wysiłku, niestety.
z jakiego powodu miałbym wybrać to drugie?
Tak jak pisałem na początku tego wątku, sens jest taki, że te drugie testy sprawdzają faktycznie czy system działa
(modulo jakieś wyjątkowe sytuacje z niedograniem API), podczas gdy te pierwsze sprawdzają tylko czy jakiś kawałek kodu działa
i w zasadzie niczego mi nie mówią.
To że takie testy są zielone, oznacza tylko że jakiś kawałek kodu działa zgodnie z asercjami w teście, ale ten kawałek kodu moze nigdy nigdzie nie być wywoływany i funkcja systemu wali HTTP500.
Oczywiście, warto mieć takie testy. Tu się zgadzam, że są istotne! Zgadzam się w 100%.
Ale ich ilość powinna musi być mała. Są koniecznie, ale niestety są też bardzo kosztowne. Zbyt kosztowne by dodać ich więcej niż kilka i zbyt kosztowne by odpalać je często, np 1-5 razy na minutę. Co potrzebujesz sprawdzić takim testem - Czy aplikacja wstaje/bootuje się, czy strzela do bazy lub innej persystencji, i po jednym teście na każdą integrację. Jakiekolwiek inne zachowanie lub szczegóły mogą się zawrzeć w testach które nie wymagają stawiania aplikacji. Niektórych rzeczy nie da się sprawdzić tylko z poziomu kodu, tak jak mówisz. Owszem. Ale takie rzeczy są w mniejszości, znaczącą część da się.
Z drugiej strony test który uderza po endpointach tak jak robi to docelowy klient i sprawdzają czy wyniki są zgodne z oczekiwaniami, potwierdza że funkcja systemu działa zgodnie z wymaganiami, niezaleznie od tego co tam się dzieje w środku. Możesz wymienić logikę systemu na hindusa który ręcznie pisze ci jsony z odpowiedzią jak chcesz.
Powiedziałbym że argument który przywołałeś jest z rodziny tych "technically correct". Czyli, tak, owszem to prawda co mówisz; jednak nie widzę żeby popierało Twoją pozycję w debacie.
Jakby - technicznie to co mówisz to prawda, ale co z tego, skoro są tak bardzo wolne.
Nadal nie masz jak wstrzyknąć moków albo fake'ów.
I bardzo dobrze! Czemu miałbym coś takiego robić? o_O Ja chce testować jak działa kod który chce statkować na produkcje, a nie jak działa mockito. Co mi z testów które są zielone dla jakiegoś mocka, jak mi sie potem prawdziwa implementacja wywali?
Co mi z testów które są zielone dla mocka
; no to, że wiesz że jeśli testy przejdą to kod Twojej aplikacji działa dokładnie tak jak powinien (przy założeniu że testy są dobrze napisane).
Mam wrażenie że potrzegasz to zbyt czarno biało. Że albo wszystkie testy są bez stawiania apki, albo wszystkie z.
Moim zdaniem powinieneś napisać kilka kluczowych testów które są potrzebne do sprawdzenia tego o czym mówisz, czy aplikacja wstanie, czy prawdziwa integracja pyknie, etc. a pozostałą część logiki swojej aplikacji bez takiej integracji. Tych które na prawdę (powiedzmy) stawiają aplikacje lub strzelają do bazy powinno być mało.
Testy powinny być deterministyczne, przede wszystkim. Jak odpalisz je 1000 razy powinieneś dostać 1000 razy ten sam wynik. 1000. Nie 999, a raz false positive/negative. Jak Twoje testy strzelają do bazy, to czy na pewno jak failują to to jest problem z kodem? Of course not. Jest miejsce na niedeterministyczne testy, ale ich powinno być mało.
Ja widziałbym to tak, że miałbyś 900 testów (nawet na małą apkę) które odpalają się bez stawiania aplikacji, + kilka "cięższych" (dodane do grupy w junicie, żeby mi sie nie odpalały cały czas), i one mogłyby postawić aplikacje, strzelić do bazy lub czegoś innego. Te 900 testów mogłyby się wykonać w 1-2 sekundy, a kilka-kilkanaście tych cięższych mogłoby kilkanaście sekund do minuty. Co tym zyskam? To że mogę pracować w prawdziwym TDD, i po każdym refaktorze i dodaniu feater'ów odpalić 900 testów w sekundę, nie przerywając swojej pracy + na koniec feature'a przed puszem odpalić pełny suite.
W momencie w którym wszystkie moje testy byłby "ciężkie" i sprawdzały wszystko, nie mógłbym tego robić, odpałabym testy rzadziej bo po pierwsze; trwają dłużej; a po drugie musiałbym mieć inne zależności, tą bazę, albo container pod tomcata.
Gdyby istniał sposób żeby uruchamianie testów na stojącej aplikacji, np 1000 testów w sekundę to byłbym jak najbardziej za. Ale niestety nie mamy takiej technologii jeszcze.