Ile kpiny jest „w sam raz?”

10

Pytanie to żartowałem, bo jestem pewien, że „to zależy”, ale mam kilka konkretnych pytań.

Pracując w oprogramowaniu, które ma wiele głębokich warstw zależności, mój zespół przyzwyczaił się do dość obszernego kpowania w celu oddzielenia każdego modułu kodu od zależności poniżej.

Dlatego byłem zaskoczony, że Roy Osherove zasugerował w tym filmie , że powinieneś używać szyderstwa tylko przez około 5% czasu. Domyślam się, że siedzimy gdzieś pomiędzy 70-90%. Od czasu do czasu widziałem też inne podobne wskazówki .

Powinienem zdefiniować, co uważam za dwie kategorie „testów integracyjnych”, które są tak odrębne, że naprawdę należy im nadać różne nazwy: 1) Testy w trakcie procesu, które integrują wiele modułów kodu oraz 2) Testy poza procesem, które mówią do baz danych, systemów plików, usług internetowych itp. Zajmuję się typem nr 1, testami integrującymi wiele modułów kodu.

Wiele wskazówek społeczności, które przeczytałem, sugeruje, że powinieneś preferować dużą liczbę izolowanych, drobnoziarnistych testów jednostkowych i niewielką liczbę gruboziarnistych kompleksowych testów integracyjnych, ponieważ testy jednostkowe dają dokładne informacje zwrotne na temat tego, gdzie dokładnie regresje mogły zostać utworzone, ale zgrubne testy, których konfiguracja jest uciążliwa, faktycznie weryfikują większą funkcjonalność systemu od początku do końca.

Biorąc to pod uwagę, wydaje się, że konieczne jest dość częste wykorzystywanie drwiny w celu izolowania tych oddzielnych jednostek kodu.

Biorąc pod uwagę model obiektowy, jak następuje:

wprowadź opis zdjęcia tutaj

... Weź również pod uwagę, że głębokość zależności naszej aplikacji jest znacznie głębsza niż mogłem zmieścić na tym obrazie, tak że pomiędzy warstwami 2-4 i 5-13 jest wiele warstw N.

Jeśli chcę przetestować jakąś prostą logiczną decyzję podejmowaną w jednostce nr 1 i jeśli każda zależność jest wstrzykiwana przez konstruktora do modułu kodu, który jest od niej zależny, tak, powiedzmy, 2, 3 i 4 są konstruktorem wstrzykiwanym do modułu 1 w obraz, wolałbym raczej wstrzykiwać makiety 2, 3 i 4 do 1.

W przeciwnym razie musiałbym zbudować konkretne wystąpienia 2, 3 i 4. Może to być trudniejsze niż dodatkowe pisanie. Często 2, 3 i 4 będą miały wymagania konstruktorskie, których spełnienie może być trudne i zgodnie z wykresem (i zgodnie z rzeczywistością naszego projektu) będę musiał zbudować konkretne wystąpienia od N do 13, aby spełnić konstruktory 2, 3 i 4.

Ta sytuacja staje się trudniejsza, gdy potrzebuję 2, 3 lub 4, aby zachowywać się w określony sposób, dzięki czemu mogę przetestować prostą logiczną decyzję w punkcie 1. Być może będę musiał zrozumieć i „mentalnie uzasadnić” cały wykres obiektu / drzewo jednocześnie, aby uzyskać 2, 3 lub 4, aby zachowywały się w niezbędny sposób. Często wydaje się o wiele łatwiej zrobić myMockOfModule2.Setup (x => x.GoLeftOrRight ()). Zwraca (new Right ()); aby sprawdzić, czy moduł 1 reaguje zgodnie z oczekiwaniami, gdy moduł 2 każe mu iść w prawo.

Gdybym miał przetestować razem konkretne przypadki 2 ... N ... 13, ustawienia testowe byłyby bardzo duże i w większości powielone. Niepowodzenia testowe mogą nie być bardzo przydatne w określaniu lokalizacji awarii regresji. Testy nie byłyby niezależne ( inny link pomocniczy ).

To prawda, że ​​często rozsądne jest przeprowadzanie testowania dolnej warstwy w oparciu o stan, a nie interakcję, ponieważ moduły te rzadko mają jakąkolwiek dalszą zależność. Wydaje się jednak, że kpina z definicji jest prawie konieczna, aby odizolować moduły powyżej najniższej pozycji.

Biorąc to wszystko pod uwagę, czy ktoś może mi powiedzieć, czego mi brakuje? Czy nasz zespół nadużywa kpiny? Czy może jest jakieś założenie w typowych wskazówkach dotyczących testowania jednostkowego, że warstwy zależności w większości aplikacji będą na tyle płytkie, że naprawdę uzasadnione jest przetestowanie wszystkich modułów kodu zintegrowanych razem (czyniąc nasz przypadek „specjalnym”)? A może inaczej, czy nasz zespół nie ogranicza odpowiednio ograniczonego kontekstu?

ardave
źródło
Wydaje mi się, że twoja aplikacja może skorzystać z luźniejszych połączeń. en.wikipedia.org/wiki/Loose_coupling
Robert Harvey
1
Or is there perhaps some assumption in typical unit testing guidance that the layers of dependency in most applications will be shallow enough that it is indeed reasonable to test all of the code modules integrated together (making our case "special")? <- To.
Robert Harvey
Warto również zauważyć: Celem testów regresyjnych (zwłaszcza testów integracyjnych) jest udowodnienie, że oprogramowanie nadal działa, niekoniecznie w celu ustalenia, gdzie się psuje. Możesz to zrobić za pomocą rozwiązywania problemów, naprawić problem, a następnie pokryć konkretne uszkodzenie dodatkowymi testami jednostkowymi.
Robert Harvey
Powinienem był wyrazić się lepiej w oryginalnym poście, mówiąc, że moduł 1 zna tylko I2, I3 i I4. Moduł 2 zna tylko I5, I6 i I7. Jedynym wątpliwym celem testowania bez użycia makiet są konkretne 2, 3 i 4 do 1, prowadzące do opisanych przeze mnie wyzwań. W przeciwnym razie skończymy z użyciem kpiny przez ponad 5% czasu.
ardave
W pewnym sensie żartowałem, że nasza sprawa jest „wyjątkowa” po przeczytaniu postu na blogu o wielu zespołach przeciwnych cennym konwencjom, ponieważ błędnie uważały, że ich sytuacja jest „wyjątkowa”. Ale jeśli tak właśnie jest w naszym przypadku, to wyjaśniałoby rozbieżność między niektórymi wytycznymi dla społeczności, które przeczytałem, a niektórymi faktycznymi doświadczeniami mojego zespołu. (5% vs 70-90%)
żarliwie

Odpowiedzi:

4

Czy nasz zespół nadużywa kpiny?

Nie na pierwszy rzut oka.

Jeśli masz 1..13 modułów, to każdy powinien mieć własne testy jednostkowe, a wszystkie zależności (nietrywialne, niezaufane) należy zastąpić wersjami testowymi. Które mogą oznaczać mocks, ale niektórzy ludzie są pedantyczne z nazewnictwa, więc podróbki, podkładek, obiektów zerowych ... niektórzy ludzie odnoszą się do wszystkich wdrożeń badań jako „imitacje”. Może to być przyczyną nieporozumień na temat tego, ile „jest właściwe”.

Osobiście nazywam wszystkie obiekty testowe „próbnymi”, ponieważ rozróżnianie ich różnorodności nie jest często przydatne. Tak długo, jak utrzymują moje testy jednostkowe szybko, odizolowane i odporne ... Nie obchodzi mnie, jak się nazywają.

Telastyn
źródło
Zastanawiałbym się wtedy, czy istnieją jakieś ogólne wskazówki dotyczące tego, kiedy najlepiej testować moduły kodu osobno, a nie testować więcej niż jeden moduł kodu zintegrowany razem. Wygląda na to, że jak tylko zintegruję dwa moduły, które w innym przypadku mógłbym odizolować, otwieram się na szereg niepożądanych problemów: brak dokładnego wskazania przyczyn regresji / niepowodzenia wielu testów dla pojedynczej regresji, nadmierna konfiguracja testów itp. Mam swój intuicyjny zmysł („słuchaj testów”), ale to pozostawiło mnie na poziomie 70–90%.
ardave
1
@ nono - Z mojego doświadczenia wynika, że ​​powinieneś testować wszystko osobno, z powodów, o których wspominasz. Jedynymi rzeczami, których nie testujesz jednostkowo w izolacji, są rzeczy, których nie możesz, ponieważ są one skierowane bezpośrednio przeciwko systemowi plików lub innemu zasobowi zewnętrznemu (w końcu coś musi to zrobić).
Telastyn
Po przeżuwaniu tego przez kilka dni, twoje wydaje się najlepszym możliwym wytłumaczeniem: gdyby użyć ścisłej definicji „próbnego” jako rodzaju podwójnego testu używanego do retrospektywnej weryfikacji interakcji / zachowania, w przeciwieństwie do podwójnego testu zastępczego lub testowy podwójny, który jest skonfigurowany wcześniej, aby symulować pewne określone zachowanie, wtedy tak, mogłem zobaczyć zakończenie na poziomie 5%.
ardave