(Dlaczego) ważne jest, aby test jednostkowy nie testował zależności?

103

Rozumiem wartość automatycznego testowania i używam go wszędzie tam, gdzie problem jest wystarczająco dokładnie określony, że mogę wymyślić dobre przypadki testowe. Zauważyłem jednak, że niektórzy ludzie tutaj i na StackOverflow kładą nacisk na testowanie tylko jednostki, a nie jej zależności. Tutaj nie widzę korzyści.

Wyśmiewanie / odgałęzienie w celu uniknięcia zależności testowych zwiększa złożoność testów. Dodaje sztuczną elastyczność / wymagania odsprzęgania do kodu produkcyjnego w celu obsługi kpiny. (Nie zgadzam się z każdym, kto twierdzi, że promuje to dobry projekt. Pisanie dodatkowego kodu, wprowadzanie takich rzeczy, jak frameworki wstrzykiwania zależności lub w inny sposób zwiększanie złożoności bazy kodu, aby uczynić rzeczy bardziej elastycznymi / podłączanymi / rozszerzalnymi / oddzielonymi bez rzeczywistego przypadku użycia, to nadmierna inżynieria, a nie dobry projekt.)

Po drugie, testowanie zależności oznacza, że ​​krytyczny kod niskiego poziomu, który jest używany wszędzie, jest testowany przy użyciu danych wejściowych innych niż te, które ktoś, kto napisał testy, wyraźnie myślał. Znalazłem wiele błędów w funkcjonowaniu niskiego poziomu, uruchamiając testy jednostkowe na funkcjonalności wysokiego poziomu bez wyśmiewania się z funkcji niskiego poziomu, od których była zależna. Najlepiej byłoby, gdyby testy jednostkowe wykazały funkcjonalność niskiego poziomu, ale zawsze zdarzają się przypadki pominięcia.

Jaka jest druga strona tego? Czy naprawdę ważne jest, aby test jednostkowy nie sprawdzał również jego zależności? Jeśli tak, dlaczego?

Edycja: Rozumiem wartość kpienia z zewnętrznych zależności, takich jak bazy danych, sieci, usługi sieciowe itp. (Podziękowania dla Anny Lear za motywowanie mnie do wyjaśnienia tego). Odniosłem się do wewnętrznych zależności , tj. Innych klas, funkcji statycznych itp. które nie mają żadnych bezpośrednich zależności zewnętrznych.

dsimcha
źródło
14
„nadinżynieria, niezbyt dobry projekt”. Będziesz musiał dostarczyć więcej dowodów niż to. Wielu ludzi nie nazwałoby tego „nad inżynierią”, ale „najlepszą praktyką”.
S.Lott,
9
@ S.Lott: Oczywiście jest to subiektywne. Po prostu nie chciałem znaleźć odpowiedzi na wiele pytań i powiedzieć, że kpina jest dobra, ponieważ uczynienie kodu możliwym do wypromowania promuje dobry projekt. Ogólnie jednak nienawidzę zajmować się kodem, który jest oddzielony od produkcji w sposób, który nie przynosi oczywistych korzyści teraz ani w dającej się przewidzieć przyszłości. Jeśli nie masz teraz wielu implementacji i nie spodziewasz się ich w dającej się przewidzieć przyszłości, to IMHO powinieneś po prostu to napisać. Jest to prostsze i nie nudzi klienta szczegółami zależności obiektu.
dsimcha
5
Ogólnie jednak nienawidzę zajmować się kodem, który jest sprzężony w sposób, który nie ma oczywistych uzasadnień oprócz złego projektu. Jest to prostsze i nie nudzi klienta elastycznością testowania rzeczy w izolacji.
S.Lott,
3
@ S.Lott: Wyjaśnienie: Miałem na myśli kod, który w znacznym stopniu wykracza poza sposób oddzielania rzeczy bez wyraźnego przypadku użycia, szczególnie tam, gdzie czyni kod lub kod klienta znacznie bardziej szczegółowymi, wprowadza jeszcze inną klasę / interfejs itp. Oczywiście nie wzywam do tego, aby kod był ściślej sprzężony niż najprostszy i najbardziej zwięzły projekt. Ponadto, gdy tworzysz linie abstrakcji przedwcześnie, zwykle kończą w niewłaściwych miejscach.
dsimcha
Zastanów się nad zaktualizowaniem pytania, aby wyjaśnić wszelkie rozróżnienia. Integracja sekwencji komentarzy jest trudna. Proszę zaktualizować kwestię doprecyzowania i skupić ją.
S.Lott,

Odpowiedzi:

116

To kwestia definicji. Test z zależnościami jest testem integracyjnym, a nie testem jednostkowym. Powinieneś także mieć pakiet testów integracyjnych. Różnica polega na tym, że pakiet testów integracyjnych może być uruchamiany w innym środowisku testowym i prawdopodobnie nie jest częścią kompilacji, ponieważ zajmuje to więcej czasu.

Dla naszego produktu: Nasze testy jednostkowe są przeprowadzane z każdą wersją, co zajmuje kilka sekund. Podzbiór naszych testów integracyjnych jest uruchamiany przy każdym odprawie i zajmuje 10 minut. Nasz pełny pakiet integracyjny jest uruchamiany każdej nocy, zajmuje 4 godziny.

Jeffrey Faust
źródło
4
Nie zapomnij o testach regresji obejmujących wykryte i naprawione błędy, aby zapobiec ich ponownemu wprowadzeniu do systemu podczas przyszłej konserwacji.
RBerteig,
2
Nie nalegałbym na definicję, nawet jeśli się z nią zgadzam. Niektóre kody mogą mieć akceptowalne zależności, takie jak StringFormatter i nadal są uwzględniane przez większość testów jednostkowych.
danidacar
2
danip: jasne definicje są ważne, i będzie nalegać na nich. Ale ważne jest również, aby zdać sobie sprawę, że te definicje są celem. Warto celować, ale nie zawsze potrzebujesz tarczy. Testy jednostkowe często zależą od bibliotek niższego poziomu.
Jeffrey Faust,
2
Ważne jest również zrozumienie koncepcji testów elewacji, które nie sprawdzają, jak komponenty pasują do siebie (jak testy integracyjne), ale testują pojedynczy komponent w izolacji. (tj. wykres obiektowy)
Ricardo Rodrigues
1
nie chodzi tylko o to, by być szybszym, ale raczej o to, aby był wyjątkowo żmudny lub niemożliwy do zarządzania, wyobraź sobie, że jeśli tego nie zrobisz, twoje drzewo egzekucji z kpin może rosnąć wykładniczo. Wyobraź sobie, że kpisz z 10 zależności w swojej jednostce, jeśli dalej naciskasz drwiąc, powiedzmy, że 1 z 10 zależności jest używanych w wielu miejscach i ma 20 własnych zależności, więc musisz kpić z + 20 innych zależności, potencjalnie podwójnie w wielu miejscach. w końcowym punkcie interfejsu API musisz wyśmiewać - np. bazę danych, abyś nie musiał jej resetować i jest to szybsze, jak powiedziałeś
FantomX1,
39

Testowanie ze wszystkimi istniejącymi zależnościami jest nadal ważne, ale bardziej dotyczy sfery testów integracyjnych, jak powiedział Jeffrey Faust.

Jednym z najważniejszych aspektów testów jednostkowych jest zapewnienie wiarygodności testów. Jeśli nie ufasz, że pozytywny test naprawdę oznacza, że ​​wszystko jest w porządku, a test zakończony niepowodzeniem naprawdę oznacza problem w kodzie produkcyjnym, twoje testy nie są tak przydatne, jak mogą być.

Aby twoje testy były wiarygodne, musisz zrobić kilka rzeczy, ale skupię się tylko na jednej z tych odpowiedzi. Musisz upewnić się, że są łatwe do uruchomienia, aby wszyscy programiści mogli je łatwo uruchomić przed wpisaniem kodu. „Łatwy do uruchomienia” oznacza, że ​​twoje testy działają szybko i nie jest wymagana żadna rozbudowana konfiguracja ani konfiguracja, aby je uruchomić. Idealnie byłoby, gdyby każdy mógł sprawdzić najnowszą wersję kodu, uruchomić testy od razu i zobaczyć, jak się sprawdzają.

Pozbycie się zależności od innych rzeczy (system plików, baza danych, usługi sieciowe itp.) Pozwala uniknąć konieczności konfigurowania i sprawia, że ​​ty i inni programiści mniej podatni na sytuacje, w których kusi cię, by powiedzieć: „Och, testy nie powiodły się, ponieważ ja nie” mieć skonfigurowany udział sieciowy. No cóż. Uruchomię je później. ”

Jeśli chcesz przetestować to, co robisz z niektórymi danymi, testy jednostkowe tego kodu logiki biznesowej nie powinny obchodzić, w jaki sposób otrzymujesz te dane. Możliwość przetestowania podstawowej logiki aplikacji bez polegania na wsparciu takich rzeczy jak bazy danych jest niesamowita. Jeśli tego nie robisz, tracisz.

PS Powinienem dodać, że zdecydowanie można nadpisać inżynierię w imię testowalności. Testowanie aplikacji pomaga złagodzić ten problem. Ale w każdym razie słabe implementacje podejścia nie powodują, że podejście jest mniej ważne. Wszystko może być niewłaściwie wykorzystane i przesadzone, jeśli nie będzie się pytać „dlaczego to robię?” podczas rozwoju.


Jeśli chodzi o wewnętrzne zależności, sprawy stają się trochę mętne. Lubię o tym myśleć, że chcę chronić moją klasę w jak największym stopniu przed zmianą z niewłaściwych powodów. Jeśli mam konfigurację taką jak ta ...

public class MyClass 
{
    private SomeClass someClass;
    public MyClass()
    {
        someClass = new SomeClass();
    }

    // use someClass in some way
}

Generalnie nie dbam o SomeClassto, jak powstaje. Chcę tylko tego użyć. Jeśli SomeClass zmieni się i teraz wymaga parametrów do konstruktora ... to nie jest mój problem. Nie powinienem zmieniać MyClass, aby to uwzględnić.

Teraz dotyczy to tylko części projektowej. Jeśli chodzi o testy jednostkowe, chcę również chronić się przed innymi klasami. Jeśli testuję MyClass, lubię wiedzieć, że nie ma żadnych zewnętrznych zależności, że SomeClass w pewnym momencie nie wprowadził połączenia z bazą danych lub innego zewnętrznego łącza.

Ale jeszcze większym problemem jest to, że wiem również, że niektóre wyniki moich metod opierają się na danych wyjściowych z niektórych metod na SomeClass. Bez wyśmiewania / eliminowania SomeClass, mógłbym nie mieć możliwości różnicowania zapotrzebowania na dane wejściowe. Jeśli mi się poszczęści, być może uda mi się skomponować moje środowisko w teście w taki sposób, że wyzwoli właściwą odpowiedź z SomeClass, ale pójście w ten sposób wprowadza złożoność do moich testów i czyni je kruchymi.

Przepisanie MyClass, aby zaakceptowało wystąpienie SomeClass w konstruktorze, pozwala mi utworzyć fałszywe wystąpienie SomeClass, które zwraca żądaną wartość (za pośrednictwem frameworku lub ręcznie). W tym przypadku generalnie nie muszę wprowadzać interfejsu. To, czy to zrobić, czy nie, jest pod wieloma względami osobistym wyborem, który może być podyktowany twoim wybranym językiem (np. Interfejsy są bardziej prawdopodobne w C #, ale na pewno nie potrzebujesz takiego w Ruby).

Adam Lear
źródło
+1 Świetna odpowiedź, ponieważ zewnętrzne zależności są przypadkiem, o którym nie myślałem, kiedy pisałem oryginalne pytanie. W odpowiedzi wyjaśniłem moje pytanie. Zobacz najnowszą edycję.
dsimcha
@dsimcha Rozszerzyłem swoją odpowiedź, aby uzyskać bardziej szczegółowe informacje na ten temat. Mam nadzieję, że to pomoże.
Adam Lear
Adam, czy możesz zasugerować język, w którym „Jeśli SomeClass zmieni się i teraz wymaga parametrów do konstruktora ... nie powinienem zmieniać MyClass”, to prawda? Przepraszam, że to zaskoczyło mnie jako niezwykły wymóg. Widzę, że nie muszę zmieniać testów jednostkowych dla MyClass, ale nie muszę zmieniać MyClass ... wow.
1
@moz Miałem na myśli to, że jeśli sposób tworzenia SomeClass jest tworzony, MyClass nie musi się zmieniać, jeśli SomeClass jest do niego wstrzykiwany, a nie tworzony wewnętrznie. W normalnych okolicznościach MyClass nie powinien martwić się o szczegóły konfiguracji SomeClass. Jeśli interfejs SomeClass ulegnie zmianie, to tak ... MyClass nadal będzie musiał zostać zmodyfikowany, jeśli wpłynie to na którąkolwiek z używanych przez niego metod.
Adam Lear
1
Jeśli wyśmiewacie SomeClass podczas testowania MyClass, jak wykryjecie, że MyClass używa SomeClass niepoprawnie lub polega na niesprawdzonym dziwactwie SomeClass, które może się zmienić?
nazwany
22

Oprócz problemu z testem integracji z jednostką należy wziąć pod uwagę następujące kwestie.

Class Widget ma zależności od klas Thingamajig i WhatsIt.

Test jednostkowy widżetu kończy się niepowodzeniem.

W której klasie leży problem?

Jeśli odpowiedziałeś „odpal debugger” lub „przeczytaj kod, dopóki go nie znajdę”, rozumiesz znaczenie testowania tylko jednostki, a nie zależności.

Potok
źródło
3
@Brook: A może zobaczysz, jakie są wyniki dla wszystkich zależności Widżetu? Jeśli wszystkie przejdą, jest to problem z Widżetem, dopóki nie zostanie udowodnione inaczej.
dsimcha
4
@dsimcha, ale teraz dodajesz złożoności w grze, aby sprawdzić etapy pośrednie. Dlaczego nie uprościć i po prostu najpierw wykonać proste testy jednostkowe? Następnie wykonaj test integracji.
asoundmove
1
@dsimcha, brzmi rozsądnie, dopóki nie przejdziesz do nietrywialnego wykresu zależności. Załóżmy, że masz złożony obiekt o głębokości ponad 3 warstw z zależnościami, zamienia się on w wyszukiwanie problemu O (N ^ 2) zamiast w O (1)
Brook
1
Ponadto moja interpretacja SRP jest taka, że ​​klasa powinna ponosić jedną odpowiedzialność na poziomie koncepcyjnym / problemowym. Nie ma znaczenia, czy wypełnienie tej odpowiedzialności wymaga zrobienia wielu różnych rzeczy, gdy patrzy się na nią na niższym poziomie abstrakcji. Jeśli doprowadzi się do skrajności, SRP byłoby sprzeczne z OO, ponieważ większość klas przechowuje dane i wykonuje na nich operacje (dwie rzeczy, gdy są oglądane na wystarczająco niskim poziomie).
dsimcha
4
@ Brook: Więcej typów nie zwiększa złożoności per se. Więcej typów jest w porządku, jeśli typy te mają sens koncepcyjny w dziedzinie problemów i sprawiają, że kod jest łatwiejszy, a nie trudniejszy do zrozumienia. Problem polega na sztucznym odsprzęganiu rzeczy, które są koncepcyjnie sprzężone na poziomie domeny problemowej (tj. Masz tylko jedną implementację, prawdopodobnie nigdy nie będzie więcej niż jedna itd.), A odsprzęganie nie odwzorowuje dobrze pojęć związanych z domeną problemową. W takich przypadkach głupotą, biurokracją i gadatliwością jest tworzenie poważnych abstrakcji wokół tego wdrożenia.
dsimcha
14

Wyobraź sobie, że programowanie jest jak gotowanie. Następnie testowanie jednostkowe jest takie samo, jak upewnianie się, że składniki są świeże, smaczne itp. Natomiast testy integracyjne to upewnianie się, że posiłek jest smaczny.

W ostatecznym rozrachunku upewnienie się, że posiłek jest pyszny (lub system działa) jest najważniejszą rzeczą, ostatecznym celem. Ale jeśli twoje składniki, to znaczy jednostki, działają, będziesz miał tańszy sposób, aby się dowiedzieć.

Rzeczywiście, jeśli możesz zagwarantować, że twoje jednostki / metody działają, istnieje większe prawdopodobieństwo, że masz działający system. Podkreślam „bardziej prawdopodobne”, niż „pewne”. Nadal potrzebujesz testów integracyjnych, tak jak nadal potrzebujesz kogoś, kto spróbuje ugotowanego posiłku i powie, że produkt końcowy jest dobry. Łatwiej będzie ci się tam dostać ze świeżymi składnikami, to wszystko.

Julio
źródło
7
A gdy testy integracyjne zakończą się niepowodzeniem, test jednostkowy może rozwiązać problem.
Tim Williscroft,
9
Aby rozciągnąć analogię: gdy okaże się, że Twój posiłek smakuje okropnie, może być konieczne przeprowadzenie dochodzenia w celu ustalenia, że ​​przyczyną był spleśniały chleb. Rezultat jest taki, że dodajesz test jednostkowy, aby sprawdzić spleśniały chleb przed gotowaniem, aby ten konkretny problem nie mógł się powtórzyć. Następnie, jeśli później wystąpi kolejny błąd posiłku, wyeliminowałeś spleśniały chleb jako przyczynę.
Kyralessa
Uwielbiam tę analogię!
wyjący
6

Testowanie jednostek poprzez ich całkowitą izolację pozwoli na przetestowanie WSZYSTKICH możliwych odmian danych i sytuacji, w których jednostka ta może zostać przesłana. Ponieważ jest odizolowany od reszty, możesz zignorować wariacje, które nie mają bezpośredniego wpływu na testowane urządzenie. to z kolei znacznie zmniejszy złożoność testów.

Testowanie przy różnych poziomach zintegrowanych zależności pozwoli przetestować określone scenariusze, które mogły nie zostać przetestowane w testach jednostkowych.

Oba są ważne. Po przeprowadzeniu testu jednostkowego niezmiennie będziesz występować bardziej złożony subtelny błąd występujący podczas integracji komponentów. Sam test integracji oznacza, że ​​testujesz system bez pewności, że poszczególne części maszyny nie zostały przetestowane. Myślenie, że można uzyskać lepszy pełny test po prostu przez wykonanie testów integracyjnych, jest prawie niemożliwe, ponieważ im więcej dodanych składników, liczba kombinacji wejściowych rośnie BARDZO szybko (myśl silnie), a utworzenie testu o wystarczającym zasięgu staje się bardzo szybko niemożliwe.

Krótko mówiąc, trzy poziomy „testów jednostkowych”, których zwykle używam w prawie wszystkich moich projektach:

  • Testy jednostkowe, wyodrębnione za pomocą próbnych lub ukrytych zależności, aby przetestować piekło pojedynczego komponentu. Idealnie byłoby spróbować pełnego pokrycia.
  • Testy integracyjne w celu przetestowania bardziej subtelnych błędów. Starannie wykonane kontrole na miejscu, które pokazują limity przypadków i typowe warunki. Pełne pokrycie często nie jest możliwe, wysiłek koncentruje się na tym, co spowodowałoby awarię systemu.
  • Testowanie specyfikacji w celu wprowadzenia różnych rzeczywistych danych do systemu, instrumentowania danych (jeśli to możliwe) i obserwowania wyników, aby upewnić się, że są one zgodne ze specyfikacją i regułami biznesowymi.

Wstrzykiwanie zależności jest jednym z bardzo skutecznych sposobów na osiągnięcie tego, ponieważ pozwala bardzo łatwo izolować komponenty do testów jednostkowych bez zwiększania złożoności systemu. Twój scenariusz biznesowy może nie uzasadniać zastosowania mechanizmu wstrzykiwania, ale twój scenariusz testowy prawie tego wymaga. To dla mnie wystarcza, aby uczynić go niezbędnym. Możesz ich również użyć do niezależnego testowania różnych poziomów abstrakcji poprzez częściowe testy integracji.

Newtopian
źródło
4

Jaka jest druga strona tego? Czy naprawdę ważne jest, aby test jednostkowy nie sprawdzał również jego zależności? Jeśli tak, dlaczego?

Jednostka. Oznacza liczbę pojedynczą.

Testowanie 2 rzeczy oznacza, że ​​masz dwie rzeczy i wszystkie zależności funkcjonalne.

Jeśli dodasz trzecią rzecz, zwiększysz zależności funkcjonalne w testach poza liniowo. Wzajemne powiązania między rzeczami rosną szybciej niż liczba rzeczy.

Istnieje n (n-1) / 2 potencjalnych zależności między n badanych pozycji.

To jest główny powód.

Prostota ma wartość.

S.Lott
źródło
2

Pamiętasz, jak po raz pierwszy nauczyłeś się robić rekurencję? Mój prof powiedział „Załóżmy, że masz metodę, która robi x” (np. Rozwiązuje Fibbonacciego dla dowolnego x). „Aby rozwiązać x, musisz wywołać tę metodę dla x-1 i x-2”. Z tych samych względów eliminacja zależności pozwala udawać, że istnieją i sprawdzać, czy bieżąca jednostka robi to, co powinna. Założeniem jest oczywiście, że testujesz zależności tak rygorystycznie.

Jest to w istocie SRP w pracy. Skupienie się na pojedynczej odpowiedzialności nawet za twoje testy, eliminuje ilość żonglerki umysłowej, którą musisz zrobić.

Michael Brown
źródło
2

(To drobna odpowiedź. Dzięki @TimWilliscroft za podpowiedź.)

Usterki można łatwiej zlokalizować, jeśli:

  • Zarówno testowany moduł, jak i każda z jego zależności są testowane niezależnie.
  • Każdy test kończy się niepowodzeniem tylko wtedy, gdy występuje błąd w kodzie objętym testem.

Działa to dobrze na papierze. Jednak, jak pokazano w opisie OP (zależności są błędne), jeśli zależności nie są testowane, trudno byłoby wskazać lokalizację błędu.

rwong
źródło
Dlaczego zależności nie byłyby testowane? Są przypuszczalnie niższe i łatwiejsze do testowania jednostkowego. Co więcej, dzięki testom jednostkowym obejmującym określony kod, łatwiej jest wskazać lokalizację usterki.
David Thornley,
2

Wiele dobrych odpowiedzi. Dodałbym także kilka innych punktów:

Testowanie jednostkowe pozwala również przetestować kod, gdy nie istnieją zależności . Na przykład ty lub twój zespół nie napisałeś jeszcze innych warstw, a może czekasz na interfejs dostarczony przez inną firmę.

Testy jednostkowe oznaczają również, że nie musisz mieć pełnego środowiska na swoim urządzeniu programistycznym (np. Baza danych, serwer WWW itp.). Chciałbym polecić silny, że wszyscy deweloperzy zrobić mieć takiego środowiska, jednak ściąć to jest, w celu repro błędów itd. Jednakże, jeśli z jakiegoś powodu nie jest możliwe, aby naśladować środowisko produkcyjne następnie testowanie jednostkowe przynajmniej daje pewien poziom Yu zaufania do twojego kodu, zanim trafi on do większego systemu testowego.

Steve
źródło
0

O aspektach projektowych: Wierzę, że nawet małe projekty korzystają z możliwości testowania kodu. Niekoniecznie musisz wprowadzać coś takiego jak Guice (często wystarczy zwykła klasa fabryczna), ale oddzielenie procesu budowy od logiki programowania daje

  • przejrzyste dokumentowanie zależności każdej klasy za pomocą interfejsu (bardzo pomocne dla osób, które są nowe w zespole)
  • klasy stają się znacznie wyraźniejsze i łatwiejsze w utrzymaniu (po umieszczeniu tworzenia brzydkiego wykresu obiektowego w osobnej klasie)
  • luźne sprzęgło (znacznie ułatwiające zmiany)
Oliver Weiler
źródło
2
Metoda: Tak, ale musisz dodać dodatkowy kod i dodatkowe klasy, aby to zrobić. Kod powinien być możliwie zwięzły, a jednocześnie czytelny. IMHO dodaje fabryki, a co nie jest nadinżynierią, chyba że udowodnisz, że potrzebujesz lub istnieje duże prawdopodobieństwo, że zapewni elastyczność, którą zapewnia.
dsimcha
0

Uh ... tutaj są dobre punkty na testach jednostkowych i integracyjnych w tych odpowiedziach!

Brakuje mi tutaj poglądów związanych z kosztami i praktycznych . To powiedziawszy, widzę wyraźnie korzyści z bardzo izolowanych / jednostkowych testów atomowych (być może wysoce niezależnych od siebie i z możliwością uruchamiania ich równolegle i bez żadnych zależności, takich jak bazy danych, system plików itp.) I (wyższego poziomu) testów integracyjnych, ale ... to także kwestia kosztów (czasu, pieniędzy, ...) i ryzyka .

Są więc inne czynniki, które są znacznie ważniejsze (jak „co przetestować” ), zanim pomyślisz o „jak przetestować” z mojego doświadczenia ...

Czy mój klient (domyślnie) płaci za dodatkową ilość testów i testów? Czy podejście bardziej oparte na testach (najpierw pisz testy przed napisaniem kodu) jest naprawdę opłacalne w moim środowisku (analiza ryzyka / kosztów awarii kodu, ludzie, specyfikacje projektu, konfiguracja środowiska testowego)? Kod jest zawsze błędny, ale czy przeniesienie testowania do wykorzystania produkcyjnego może być bardziej opłacalne (w najgorszym przypadku!)?

Zależy to również w dużej mierze od jakości kodu (standardów), ram, IDE, zasad projektowania itp., Których przestrzegasz Ty i Twój zespół, a także od ich doświadczenia. Dobrze napisany, łatwo zrozumiały, wystarczająco dobrze udokumentowany (najlepiej samodokumentujący), modułowy ... kod wprowadza prawdopodobnie mniej błędów niż na odwrót. Tak więc rzeczywista „potrzeba”, presja lub ogólne koszty / ryzyko związane z naprawą / błędami w przypadku obszernych testów mogą nie być wysokie.

Przejdźmy do skrajności, gdzie sugerował współpracownik z mojego zespołu, musimy spróbować przetestować jednostkowo nasz kod warstwy modelu czystego Java EE z pożądanym 100% pokryciem dla wszystkich klas wewnątrz i wyśmiewaniem bazy danych. Lub menedżer, który chciałby, aby testy integracyjne obejmowały 100% wszystkich możliwych przypadków użycia w świecie rzeczywistym i przepływów pracy w interfejsie sieciowym, ponieważ nie chcemy ryzykować niepowodzenia żadnego przypadku użycia. Ale mamy napięty budżet w wysokości około 1 miliona euro, dość napięty plan kodowania wszystkiego. Środowisko klienta, w którym potencjalne błędy aplikacji nie byłyby bardzo dużym zagrożeniem dla ludzi lub firm. Nasza aplikacja zostanie przetestowana wewnętrznie z (niektórymi) ważnymi testami jednostkowymi, testami integracji, testami kluczowych klientów z zaprojektowanymi planami testów, fazą testów itp. Nie tworzymy aplikacji dla niektórych fabryk jądrowych lub produkcji farmaceutycznej!

Sam próbuję napisać test, jeśli to możliwe, i rozwinąć się podczas testowania mojego kodu. Ale często robię to od góry do dołu (testy integracyjne) i staram się znaleźć dobry punkt, w którym „wyciąć warstwę aplikacji” do ważnych testów (często w warstwie modelu). (ponieważ często chodzi o „warstwy”)

Ponadto kod testu jednostkowego i integracyjnego nie przychodzi bez negatywnego wpływu na czas, pieniądze, konserwację, kodowanie itp. Jest fajny i należy go stosować, ale należy zachować ostrożność i rozważyć konsekwencje przy rozpoczynaniu lub po 5 latach wielu opracowanych testów kod.

Powiedziałbym więc, że tak naprawdę zależy to od zaufania i oceny kosztów / ryzyka / korzyści ... jak w prawdziwym życiu, w którym nie możesz i nie chcesz biegać z wieloma lub 100% mechanizmami bezpieczeństwa.

Dziecko może i powinno gdzieś wspiąć się na górę, może spaść i zranić się. Samochód może przestać działać, ponieważ wlałem niewłaściwe paliwo (nieprawidłowe wejście :)). Tost może zostać spalony, jeśli przycisk czasu przestanie działać po 3 latach. Ale ja nigdy, nie chcę jechać autostradą i trzymać w rękach moją odłączoną kierownicę :)

Andreas Dietrich
źródło