Czy istnieje zbyt wiele testów jednostkowych?

139

Zadanie polegało mi na napisaniu testów jednostkowych dla istniejącej aplikacji. Po zakończeniu pierwszego pliku mam 717 linii kodu testowego na 419 linii oryginalnego kodu.

Czy ten współczynnik stanie się niemożliwy do zarządzania, gdy zwiększymy zasięg naszego kodu?

Moje rozumienie testów jednostkowych polegało na przetestowaniu każdej metody w klasie, aby upewnić się, że każda metoda działa zgodnie z oczekiwaniami. Jednak w prośbie o wycofanie mój lider techniczny zauważył, że powinienem skupić się na testowaniu na wyższym poziomie. Zasugerował przetestowanie 4-5 przypadków użycia, które są najczęściej używane w danej klasie, zamiast wyczerpującego testowania każdej funkcji.

Ufam komentarzowi mojego kierownika technicznego. Ma więcej doświadczenia niż ja i ma lepszy instynkt, jeśli chodzi o projektowanie oprogramowania. Ale w jaki sposób wieloosobowy zespół pisze testy dla tak dwuznacznego standardu; to znaczy, skąd mam poznać moich rówieśników i podzielam ten sam pomysł dotyczący „najczęstszych przypadków użycia”?

Dla mnie 100% pokrycie testem jednostkowym jest wzniosłym celem, ale nawet gdybyśmy osiągnęli tylko 50%, wiedzielibyśmy, że 100% z tych 50% zostało objętych. W przeciwnym razie pisanie testów dla części każdego pliku pozostawia dużo miejsca do oszukiwania.

użytkownik2954463
źródło
145
To zależy. Czy piszesz grę w kółko i krzyżyk, czy piszesz kod do zarządzania reaktorem jądrowym?
Bryan Oakley
11
Przy wystarczającej liczbie testów jednostkowych można wykryć egzotyczne problemy z implementacją sprzętu, takie jak błąd Pentium FDIV lub korelacje w kryptograficznych prymitywach, więc wydaje się, że nie ma sztywnego limitu, który nie byłby użyteczny. Tylko praktyczny limit, kiedy jest to zbyt kosztowne.
Nat
5
Testowanie na wyższych poziomach zapewni lepszą perspektywę rzeczywistego zasięgu. Przez rzeczywisty zasięg mam na myśli to, że bardziej prawdopodobne jest to podczas regularnego korzystania z systemu. Tego rodzaju zasięg chcesz najpierw osiągnąć. W 50%, które ostatnio zostaną osiągnięte, może mieć YAGNI lub martwy kod, który po usunięciu przyczyni się również do zwiększenia ogólnego zasięgu.
Laiv
5
Jeśli otrzymasz za dużo testów (których w tej chwili nie masz), najbardziej prawdopodobnym problemem jest to, że testowany kod wykonuje zbyt wiele. Tak więc pojedyncza odpowiedzialność nie jest przestrzegana. Gdy kod jest dobrze podzielony, testowanie również nie spowoduje dużego obciążenia. Jeśli klasy dużo zrobią, mają wiele skutków ubocznych itp., Stanie się koszmarem.
Luc Franken
12
Dokument testowy sqlite to zabawna lektura: sqlite.org/testing.html . Cytat: „biblioteka SQLite składa się z około 122,9 KSLOC kodu C. Dla porównania, projekt ma 745 razy więcej kodu testowego i skryptów testowych - 91596.1 KSLOC.”
user60561

Odpowiedzi:

180

Tak, ze 100% pokryciem napiszesz kilka niepotrzebnych testów. Niestety, jedynym niezawodnym sposobem ustalenia, które testy nie są potrzebne, jest napisanie ich wszystkich, a następnie odczekanie około 10 lat, aby zobaczyć, które z nich nigdy nie zawiodły.

Prowadzenie wielu testów zwykle nie jest problematyczne. Wiele zespołów ma zautomatyzowane testy integracyjne i systemowe oprócz 100% pokrycia testami jednostkowymi.

Nie jesteś jednak w fazie konserwacji testowej, grasz nadrabiając zaległości. O wiele lepiej jest mieć 100% swoich zajęć przy 50% pokryciu testowym niż 50% swoich zajęć przy 100% pokryciu testowym, a twoja szansa wydaje się próbować zmusić cię do odpowiedniego przydzielenia czasu. Po ustaleniu linii bazowej, następnym krokiem jest zazwyczaj naciskanie na 100% w plikach, które są zmieniane w przyszłości.

Karl Bielefeldt
źródło
11
Dzięki za odpowiedź. Pomogło mi to postawić pytanie w perspektywie i rozwiązać prawdziwy problem - moje podejście! +1
użytkownik2954463
43
@astra Twoje podejście nie jest takie złe. Dobrze jest zapytać dlaczego. Aby odpowiedzieć na inne pytanie, doskonałe pytanie: „Skąd mam poznać moich rówieśników i podzielam ten sam pomysł dotyczący„ najczęstszych przypadków użycia ”? Sprawiasz, że patrzą na twoje testy. Spójrz na ich. Porozmawiaj o nich. Nauczysz się dużo, a może i oni. Testy przeglądu kodu rzadko są stratą czasu. Chociaż zwykle robię kopalnie w terminalu, a nie w sali konferencyjnej
candied_orange
18
Test, który nigdy nie
zawiedzie od
24
Pragmatycznie można przyjąć odwrotne podejście. Napisz testy, które Twoim zdaniem obejmują typowe przypadki. Ale za każdym razem, gdy napotkasz awarię, napisz test, aby objąć ten obszar.
stannius
10
@Pharap Moim jedynym problemem z tą odpowiedzią jest to, że istnieje domniemane założenie, że test może wnieść wartość dodaną tylko w przypadku niepowodzenia. Dobry test jednostkowy zapewnia również świetną formę żywej dokumentacji. Przydaje to również wartość dodaną podczas pisania testu, zmuszając do myślenia o możliwości ponownego użycia / łączenia / kapsułkowania. Nieprzetestowany kod z mojego doświadczenia jest zwykle nieelastycznym monolitycznym zwierzęciem.
ArTs
66

Jeśli pracowałeś na dużych bazach kodu utworzonych za pomocą Test Driven Development, już wiesz, że może istnieć coś takiego jak zbyt wiele testów jednostkowych. W niektórych przypadkach większość prac rozwojowych polega na aktualizacji testów niskiej jakości, które najlepiej wdrożyć jako kontrole niezmiennicze, wstępne i dodatkowe w odpowiednich klasach w czasie wykonywania (tj. Testowanie jako efekt uboczny testu wyższego poziomu ).

Innym problemem jest tworzenie projektów niskiej jakości, przy użyciu technik projektowania opartych na kulturze ładunkowej, które powodują rozprzestrzenianie się rzeczy do przetestowania (więcej klas, interfejsów itp.). W takim przypadku wydaje się, że obciążeniem jest aktualizacja kodu testowego, ale prawdziwym problemem jest projekt niskiej jakości.

Frank Hileman
źródło
16
Uznane za wskazanie warunków wstępnych, warunków dodatkowych i niezmienników należy traktować jako badanie jednostkowe. W ten sposób każde użycie jest testem jednostkowym, gdy ten kod debugowania jest aktywny.
Persixty
To świetna odpowiedź i doskonale pasuje do mojego doświadczenia.
Tony Ennis
I jeszcze jeden problem: jeśli bramkowałeś meldunki (naprawdę powinieneś!) Mając duże ilości niskiej jakości, być może nawet długotrwałe testy spowolnią wszystko bez żadnych realnych korzyści. A potem oczywiście fajny fakt, że zmieniasz jedną rzecz w klasie i setki testów kończy się niepowodzeniem.
Voo
3
To zdecydowanie lepsza odpowiedź niż zaakceptowana! „W niektórych przypadkach większość prac rozwojowych polega na aktualizacji testów niskiej jakości” - doświadczyłem tego i jest do bani. Pod pewnymi względami więcej niż brak testów.
Benjamin Hodgson
36

Odpowiedzi na twoje pytania

Czy istnieje zbyt wiele testów jednostkowych?

Jasne ... Na przykład możesz mieć wiele testów, które na pierwszy rzut oka wydają się różne, ale naprawdę testują to samo (logicznie zależą od tych samych linii testowanego „ciekawego” kodu aplikacji).

Lub możesz przetestować wewnętrzne elementy swojego kodu, które nigdy nie pojawiają się na zewnątrz (tj. Nie są częścią żadnej umowy dotyczącej interfejsu), gdzie można spierać się o to, czy ma to w ogóle sens. Na przykład dokładne sformułowanie wewnętrznych komunikatów dziennika lub cokolwiek innego.

Zadanie polegało mi na napisaniu testów jednostkowych dla istniejącej aplikacji. Po zakończeniu pierwszego pliku mam 717 linii kodu testowego na 419 linii oryginalnego kodu.

To wydaje mi się całkiem normalne. Twoje testy poświęcają wiele linii kodu na konfigurację i porzucenie na dodatek do rzeczywistych testów. Współczynnik może się poprawić lub nie. Sam jestem dość obciążony testami i często inwestuję w testy więcej czasu i lokalizacji niż w rzeczywisty kod.

Czy ten współczynnik stanie się niemożliwy do zarządzania, gdy zwiększymy zasięg naszego kodu?

Współczynnik nie uwzględnia tak wiele. Istnieją inne cechy testów, które sprawiają, że nie można nimi zarządzać. Jeśli regularnie dokonujesz refaktoryzacji całej gamy testów, wykonując raczej proste zmiany w kodzie, powinieneś dobrze przyjrzeć się przyczynom. Nie chodzi o to, ile masz linii, ale o to, jak podchodzisz do kodowania testów.

Moje rozumienie testów jednostkowych polegało na przetestowaniu każdej metody w klasie, aby upewnić się, że każda metoda działa zgodnie z oczekiwaniami.

Jest to poprawne w przypadku testów „jednostkowych” w ścisłym tego słowa znaczeniu. Tutaj „jednostka” jest czymś w rodzaju metody lub klasy. Celem testów „jednostkowych” jest przetestowanie tylko jednej konkretnej jednostki kodu, a nie całego systemu. Idealnie byłoby usunąć całą resztę systemu (używając podwójnych lub whatnot).

Jednak w prośbie o wycofanie mój lider techniczny zauważył, że powinienem skupić się na testowaniu na wyższym poziomie.

Potem wpadłeś w pułapkę, zakładając, że ludzie rzeczywiście mieli na myśli testy jednostkowe, kiedy mówili , że testy jednostkowe. Spotkałem wielu programistów, którzy mówią „test jednostkowy”, ale mają na myśli coś zupełnie innego.

Zasugerował przetestowanie 4-5 przypadków użycia, które są najczęściej używane w danej klasie, zamiast wyczerpującego testowania każdej funkcji.

Jasne, samo skoncentrowanie się na 80% ważnego kodu również zmniejsza obciążenie ... Doceniam to, że wysoko oceniasz swojego szefa, ale nie wydaje mi się to optymalnym wyborem.

Dla mnie 100% pokrycie testem jednostkowym jest wzniosłym celem, ale nawet gdybyśmy osiągnęli tylko 50%, wiedzielibyśmy, że 100% z tych 50% zostało objętych.

Nie wiem, co to jest „zasięg testu jednostkowego”. Zakładam, że masz na myśli „pokrycie kodu”, tzn. Że po uruchomieniu zestawu testów każda linia kodu (= 100%) została wykonana co najmniej raz.

To niezły wskaźnik, ale zdecydowanie nie najlepszy standard, na jaki można strzelać. Samo wykonanie wierszy kodu nie jest całym obrazem; nie uwzględnia to na przykład różnych ścieżek poprzez skomplikowane, zagnieżdżone gałęzie. Jest to bardziej wskaźnik, który wskazuje palcem na fragmenty kodu, które są testowane zbyt mało (oczywiście, jeśli klasa obejmuje 10% lub 5% pokrycia kodu, coś jest nie tak); z drugiej strony 100% pokrycia nie powie ci, czy przetestowałeś wystarczająco dużo, czy poprawnie.

Testy integracyjne

Denerwuje mnie to znacznie, gdy ludzie domyślnie dzisiaj mówią o testach jednostkowych . Moim zdaniem (i doświadczenie) testy jednostkowe są świetne dla bibliotek / interfejsów API; w obszarach bardziej zorientowanych na biznes (gdzie mówimy o przypadkach użycia, takich jak pytanie), niekoniecznie są one najlepszą opcją.

Dla ogólnego kodu aplikacji i dla przeciętnego biznesu (gdzie ważne jest zarabianie pieniędzy, dotrzymywanie terminów i spełnianie zadowolenia klienta, a przede wszystkim chcesz unikać błędów, które są bezpośrednio w twarz użytkownika lub mogą prowadzić do prawdziwych katastrof - nie jesteśmy mówiąc o uruchomieniu rakiety NASA), testy integracyjne lub funkcjonalne są znacznie bardziej przydatne.

Te idą w parze z rozwojem opartym na zachowaniu lub opracowaniem opartym na cechach; z definicji nie działają one z (ścisłymi) testami jednostkowymi.

Krótko mówiąc, test integracji / funkcji ćwiczy cały stos aplikacji. W aplikacji internetowej działałoby to tak, jakby przeglądarka przeglądała aplikację (i nie, oczywiście nie musi to być takie uproszczone, istnieją bardzo potężne ramy do tego celu - sprawdź http: // ogórek. Io na przykład).

Och, aby odpowiedzieć na ostatnie pytania: cały zespół ma wysoki zasięg testu, upewniając się, że nowa funkcja jest programowana dopiero po jej wdrożeniu i niepowodzeniu. I tak, to oznacza każdą funkcję. To gwarantuje Ci 100% (pozytywny) pokrycie funkcji. Z definicji gwarantuje, że funkcja aplikacji nigdy nie zniknie. Nie gwarantuje 100% pokrycia kodu (na przykład, jeśli aktywnie nie zaprogramujesz funkcji negatywnych, nie będziesz obsługiwał obsługi błędów / obsługi wyjątków).

Nie gwarantuje to aplikacji wolnej od błędów; oczywiście będziesz chciał pisać testy funkcji dla oczywistych lub bardzo niebezpiecznych sytuacji buggy, złych danych wejściowych użytkownika, hakowania (na przykład zarządzania sesjami, bezpieczeństwa itp.) itp .; ale nawet programowanie testów pozytywnych ma ogromne zalety i jest całkiem wykonalne dzięki nowoczesnym, potężnym frameworkom.

Testy funkcji / integracji oczywiście mają swoją własną puszkę robaków (np. Wydajność; testowanie redundantne frameworków stron trzecich; ponieważ zwykle nie używasz dublowania, z mojego doświadczenia też trudniej jest napisać ...), ale ja d weź aplikację przetestowaną w 100% pod kątem dodatnich funkcji w stosunku do aplikacji przetestowanej w 100% pod kątem zasięgu (nie biblioteki!)

AnoE
źródło
1
Testy integracyjne są świetne, ale nie zastępują testów jednostkowych, również nie dla aplikacji biznesowych. Jest z nimi wiele problemów: a) z definicji zajmują dużo czasu (oznacza to również, że testy przyrostowe są prawie bezużyteczne), b) sprawiają, że niezwykle trudno jest wskazać rzeczywisty problem (oh 50 testów integracyjnych właśnie nie powiodło się, jaka zmiana spowodowała to?) ic) wielokrotnie pokrywają te same ścieżki kodu.
Voo
1
a) stanowi problem, ponieważ sprawia, że ​​przeprowadzanie testów na bramkowanych odprawach jest uciążliwe i zmniejsza prawdopodobieństwo, że programiści będą uruchamiać testy wielokrotnie podczas opracowywania, co w połączeniu z b) zmniejsza wydajność i zdolność do szybkiego diagnozowania błędów. c) oznacza, że ​​zmiana jednej małej rzeczy może łatwo spowodować, że dziesiątki lub setki (tam były) testów integracyjnych zawiodą, co oznacza, że ​​poświęcisz mnóstwo czasu na ich naprawianie. Oznacza to również, że testy integracyjne testują głównie szczęśliwe ścieżki, ponieważ pisanie tych testów jest uciążliwe lub niemożliwe.
Voo
1
@Voo, wszystko co napisałeś jest prawdą i, o ile mogę powiedzieć, wspomniałem już o wszystkich problemach, które zauważyłeś w odpowiedzi ...
AnoE
Jeśli zgadzasz się z tym podsumowaniem, naprawdę nie rozumiem, jak dojść do wniosku, że wolisz testy integracyjne niż testy jednostkowe. Kompleksowe testy integracyjne dużych programów trwają godziny, a nawet dni, są świetne, ale są prawie bezużyteczne podczas rzeczywistego programowania. A twoje testy akceptacyjne (które wszyscy robią, prawda?) Wychwycą wiele tych samych problemów, które wykryłyby testy integracyjne, które zostałyby pominięte przez testy jednostkowe - jednak nie jest odwrotnie.
Voo
24

Tak, możliwe jest przeprowadzenie zbyt wielu testów jednostkowych. Jeśli na przykład masz 100% pokrycia testami jednostkowymi i nie masz testów integracyjnych, masz wyraźny problem.

Niektóre scenariusze:

  1. Przeprojektowujesz swoje testy do konkretnej implementacji. Następnie musisz zrezygnować z testów jednostkowych podczas refaktoryzacji, nie mówiąc już o zmianie implementacji (bardzo częsty problem podczas przeprowadzania optymalizacji wydajności).

    Dobra równowaga między testami jednostkowymi a testami integracji zmniejsza ten problem bez utraty znacznego zasięgu.

  2. Możesz mieć rozsądne pokrycie każdego zatwierdzenia 20% testów, które masz, pozostawiając pozostałe 80% na integrację lub przynajmniej osobne testy; Głównymi negatywnymi skutkami, które widzisz w tym scenariuszu, są powolne zmiany, ponieważ musisz długo czekać na wykonanie testów.

  3. Zmieniasz zbyt wiele kodu, aby umożliwić Ci jego przetestowanie; na przykład widziałem wiele nadużyć IoC na komponentach, które nigdy nie będą wymagały modyfikacji lub przynajmniej generalizacja ich jest kosztowna i ma niski priorytet, ale ludzie poświęcają dużo czasu na generalizację i refaktoryzację, aby umożliwić ich testowanie jednostkowe .

W szczególności zgadzam się z sugestią uzyskania 50% pokrycia na 100% plików, zamiast 100% pokrycia na 50% plików; skoncentruj swoje początkowe wysiłki na najczęstszych przypadkach pozytywnych i najniebezpieczniejszych przypadkach negatywnych, nie inwestuj zbyt wiele w obsługę błędów i nietypowe ścieżki, nie dlatego, że nie są one ważne, ale dlatego, że masz ograniczony czas i nieskończony wszechświat testowy, więc musisz nadać priorytet każdej sprawie.

Bruno Guardia
źródło
2
Nie jest to problem z testami jednostkowymi, ale z powodu błędnych priorytetów organizacji, wymagając określonej liczby do pokrycia testów jednostkowych bez wydawania środków na tworzenie i wykonywanie odpowiednich testów na innych poziomach.
jwenting
2
Zgadzam się zdecydowanie na punkcie 3, a także rozszerzyłbym go na ręczne przekazywanie instancji klas niższego poziomu do klas wyższego poziomu. Jeśli coś na wysokim poziomie polega na czymś na niskim poziomie, aby coś zrobić, to jest w porządku. Jeśli ukrywa to szczegóły przed dzwoniącymi, nazwałbym to dobrym projektem. Ale jeśli następnie włączysz element niskiego poziomu do interfejsu elementu wysokiego poziomu i sprawisz, że dzwoniący przekażą go, ponieważ dzięki temu twoje testy są ładne, teraz ogon macha psem. (Jeśli coś niskiego poziomu jest ponownie używane w wielu miejscach i bardzo się zmienia, to zmienia rzeczy. Z mojego doświadczenia, które nie było typowe.)
John
Uwielbiam twój opis @johncip, zdecydowanie jest to częsty przykład tego, jak miła klasa robi się okropna, dodając do konstruktora zestaw niepotrzebnych wymaganych parametrów ...
Bruno Guardia
19

Pamiętaj, że każdy test ma koszt, a także korzyść. Wady obejmują:

  • test musi być napisany;
  • test zajmuje (zazwyczaj bardzo niewielką ilość) czasu;
  • test musi być przeprowadzony za pomocą kodu - testy muszą się zmieniać, kiedy zmieniają się API, które testują;
  • być może będziesz musiał zmienić swój projekt, aby napisać test (chociaż te zmiany są zwykle na lepsze).

Jeśli koszty przewyższają korzyści, lepiej nie pisać testu. Na przykład, jeśli funkcjonalność jest trudna do przetestowania, interfejs API często się zmienia, poprawność jest stosunkowo nieistotna, a szansa na znalezienie usterki w teście jest niska, prawdopodobnie lepiej nie pisać.

Jeśli chodzi o konkretny stosunek testów do kodu, jeśli kod jest wystarczająco gęsty pod względem logicznym, wówczas ten stosunek może być uzasadniony. Jednak prawdopodobnie nie warto utrzymywać tak wysokiego współczynnika w typowej aplikacji.

Sekret Solomonoffa
źródło
12

Tak, istnieje coś takiego jak zbyt wiele testów jednostkowych.

Chociaż testy są dobre, każdy test jednostkowy to:

  • Potencjalne obciążenie związane z utrzymaniem, ściśle związane z interfejsem API

  • Czas, który można poświęcić na coś innego

  • Kawałek czasu w pakiecie testów jednostkowych
  • Może nie dodawać żadnej rzeczywistej wartości, ponieważ jest to w rzeczywistości duplikat jakiegoś innego testu mającego niewielką szansę, że jakiś inny test przejdzie i test zakończy się niepowodzeniem.

Mądrze jest dążyć do 100% pokrycia kodu, ale wcale nie oznacza to zestawu testów, z których każdy niezależnie zapewnia 100% pokrycia kodu w określonym punkcie wejścia (funkcja / metoda / wywołanie itp.).

Chociaż biorąc pod uwagę, jak trudno jest osiągnąć dobry zasięg i wyeliminować błędy, prawdą jest prawdopodobnie to, że istnieje coś takiego jak „złe testy jednostkowe” i „zbyt wiele testów jednostkowych”.

Pragmatyka dla większości kodów wskazuje:

  1. Upewnij się, że masz 100% pokrycia punktów wejścia (wszystko jest jakoś testowane) i staraj się być blisko 100% pokrycia kodu ścieżek „bezbłędnych”.

  2. Przetestuj wszystkie odpowiednie wartości min / maks. Lub rozmiary

  3. Przetestuj wszystko, co uważasz za zabawny przypadek specjalny, w szczególności „nieparzyste” wartości.

  4. Gdy znajdziesz błąd, dodaj test jednostkowy, który by go ujawnił i zastanów się, czy należy dodać podobne przypadki.

W przypadku bardziej złożonych algorytmów rozważ również:

  1. Przeprowadzam masowe testy większej liczby przypadków.
  2. Porównywanie wyników do implementacji „brute-force” i sprawdzanie niezmienników.
  3. Korzystanie z pewnej metody generowania przypadkowych przypadków testowych i sprawdzanie siły brutalnej i warunków dodatkowych, w tym niezmienników.

Na przykład sprawdź algorytm sortowania z losowymi danymi wejściowymi, a sprawdzenie poprawności danych jest sortowane na końcu przez skanowanie.

Powiedziałbym, że twój lider technologiczny proponuje testy „minimalnej liczby odsłonięcia”. Oferuję „najwyższą jakość testowania jakości”, a pomiędzy nimi jest spektrum.

Być może twój senior wie, że komponent, który budujesz, zostanie osadzony w jakimś większym elemencie i jednostka zostanie bardziej dokładnie przetestowana po zintegrowaniu.

Kluczową lekcją jest dodawanie testów po wykryciu błędów. Co prowadzi mnie do najlepszej lekcji na temat opracowywania testów jednostkowych:

Skoncentruj się na jednostkach, a nie na podjednostkach. Jeśli budujesz jednostkę z podjednostek, napisz bardzo podstawowe testy dla podjednostek, aż będą one wiarygodne i uzyskaj lepszy zasięg, testując podjednostki za pomocą ich jednostek kontrolnych.

Więc jeśli piszesz kompilator i musisz napisać tablicę symboli (powiedzmy). Uruchom tabelę symboli za pomocą podstawowego testu, a następnie pracuj nad (powiedzmy) parserem deklaracji, który wypełnia tabelę. Dalsze testy dodawaj do jednostki autonomicznej tabeli symboli tylko wtedy, gdy znajdziesz w niej błędy. W przeciwnym razie zwiększ zasięg przez testy jednostkowe analizatora składni deklaracji, a później całego kompilatora.

To daje najlepszy zwrot za grosze (jednym testem całości jest testowanie wielu komponentów) i pozostawia większą pojemność na przeprojektowanie i udoskonalenie, ponieważ tylko testy „zewnętrznego” interfejsu są używane w testach, które wydają się być bardziej stabilne.

W połączeniu z warunkami wstępnymi testowania kodu debugowania, warunkami dodatkowymi, w tym niezmiennikami na wszystkich poziomach, uzyskuje się maksymalny zasięg testu od minimalnej implementacji testu.

Persixty
źródło
4
Nie powiedziałbym, że 100% zasięgu jest pragmatyczne. 100% zasięgu to niezwykle wysoki standard.
Bryan Oakley
Niestety, nawet metoda losowa może nie zawierać błędów. Dowody nie mogą zastąpić dowodów, nawet jeśli są nieformalne.
Frank Hileman
@BryanOakley Point podjęte. To przesada. Ale ważniejsze jest, aby się do niego zbliżyć, niż ludziom się podoba. „Przetestowałem łatwą ścieżkę, w której wszystko jest dobrze” zawsze będzie powodować problemy później.
Persixty
@FrankHileman Pytanie nie brzmiało: „Czy testy jednostkowe są dobrym zamiennikiem starannego projektowania oprogramowania, logiki sprawdzania statycznego i algorytmów sprawdzających”, wtedy odpowiedź brzmi „nie”. Żadna z tych metod nie wytworzy wysokiej jakości oprogramowania we własnym zakresie.
Persixty
3

Po pierwsze, niekoniecznie jest problemem mieć więcej linii testowych niż kodu produkcyjnego. Kod testowy jest (lub powinien być) liniowy i łatwy do zrozumienia - jego niezbędna złożoność jest bardzo, bardzo niska, niezależnie od tego, czy kod produkcyjny jest. Jeśli złożoność testów zacznie zbliżać się do złożoności kodu produkcyjnego, prawdopodobnie masz problem.

Tak, możliwe jest posiadanie zbyt wielu testów jednostkowych - prosty eksperyment myślowy pokazuje, że możesz kontynuować dodawanie testów, które nie zapewniają dodatkowej wartości, i że wszystkie te dodane testy mogą zahamować przynajmniej niektóre refaktoryzacje.

Rada, by przetestować tylko najczęstsze przypadki, jest, moim zdaniem, wadliwa. Mogą one działać jak testy dymu, aby zaoszczędzić czas na testowanie systemu, ale naprawdę cenne testy wychwytują przypadki, które są trudne do wykonania w całym systemie. Na przykład kontrolowane wstrzykiwanie błędów błędów alokacji pamięci może być wykorzystane do ćwiczenia ścieżek odzyskiwania, które w przeciwnym razie mogłyby być całkowicie nieznanej jakości. Lub przekaż zero jako wartość, o której wiesz, że zostanie wykorzystana jako dzielnik (lub liczba ujemna, która będzie zrootowana do kwadratu) i upewnij się, że nie otrzymasz nieobsługiwanego wyjątku.

Kolejne najcenniejsze testy to te, które wykorzystują ekstremalne granice lub punkty graniczne. Na przykład funkcja, która akceptuje (w oparciu o 1) miesiące w roku, powinna zostać przetestowana na 0, 1, 12 i 13, abyś wiedział, że poprawne-nieprawidłowe przejścia są na właściwym miejscu. Nadmierne testowanie wymaga również użycia 2..11 do tych testów.

Jesteś w trudnej sytuacji, ponieważ musisz pisać testy dla istniejącego kodu. Łatwiej jest zidentyfikować przypadki brzegowe podczas pisania (lub pisania) kodu.

Toby Speight
źródło
3

Moje rozumienie testów jednostkowych polegało na przetestowaniu każdej metody w klasie, aby upewnić się, że każda metoda działa zgodnie z oczekiwaniami.

To zrozumienie jest błędne.

Testy jednostkowe zweryfikować zachowanie na jednostki badanej .

W tym sensie jednostka niekoniecznie jest „metodą w klasie”. Podoba mi się definicja jednostki autorstwa Roy Osherove w The Art of Unit Testing :

Jednostka to cały kod produkcyjny, który ma ten sam powód do zmiany.

Na tej podstawie test jednostkowy powinien zweryfikować każde pożądane zachowanie kodu. Gdzie „pożądanie” mniej więcej pochodzi z wymagań.


Jednak w prośbie o wycofanie mój lider techniczny zauważył, że powinienem skupić się na testowaniu na wyższym poziomie.

Ma rację, ale w inny sposób niż myśli.

Z twojego pytania rozumiem, że jesteś „oddanym testerem” w tym projekcie.

Dużym nieporozumieniem jest to, że oczekuje on od ciebie pisania testów jednostkowych (w przeciwieństwie do „testowania za pomocą frameworka testowego”). Pisanie testów ynit jest obowiązkiem programistów , a nie testerów (w idealnym świecie, wiem ...). Z drugiej strony otagowałeś to pytanie TDD, co implikuje dokładnie to.

Twoim zadaniem jako testera jest napisanie (lub ręczne wykonanie) testów modułu i / lub aplikacji. Tego rodzaju testy powinny przede wszystkim sprawdzać, czy wszystkie jednostki działają płynnie. Oznacza to, że musisz wybrać przypadki testowe, aby każda jednostka została wykonana co najmniej raz . A ta kontrola polega na tym, że się uruchamia. Rzeczywisty wynik jest mniej ważny, ponieważ może ulec zmianie wraz z przyszłymi wymaganiami.

Aby jeszcze raz podkreślić analogię zrzutu samochodu: Ile testów wykonuje się samochodem na końcu linii montażowej? Dokładnie jeden: sam musi jechać na parking ...

Chodzi o to:

Musimy zdawać sobie sprawę z różnicy między „testami jednostkowymi” a „testowaniem automatycznym przy użyciu ram testów jednostkowych”.


Dla mnie 100% pokrycie testem jednostkowym jest wzniosłym celem, ale nawet gdybyśmy osiągnęli tylko 50%, wiedzielibyśmy, że 100% z tych 50% zostało objętych.

Testy jednostkowe są siatką bezpieczeństwa. Dają one pewność byłaby kodu w celu zmniejszenia długu technicznego lub dodać nowe zachowanie nie obawiając się przełamać już wdrożony zachowanie.

Nie potrzebujesz 100% pokrycia kodu.

Ale potrzebujesz 100% pokrycia zachowań. (Tak, zasięg kodu i zasięg zachowania w jakiś sposób korelują, ale ze względu na to nie są identyczne).

Jeśli masz mniej niż 100% pokrycia zachowań, pomyślne uruchomienie zestawu testów nic nie znaczy, ponieważ mogłeś zmienić niektóre z niesprawdzonych zachowań. Zostaniesz zauważony przez twojego klienta następnego dnia po przejściu twojego wydania do sieci ...


Wniosek

Niewiele testów jest lepszych niż brak testu. Bez wątpienia!

Ale nie ma czegoś takiego jak zbyt wiele testów jednostkowych.

Wynika to z faktu, że każdy test jednostkowy weryfikuje jedno oczekiwanie dotyczące zachowania kodów . Nie możesz napisać więcej testów jednostkowych, niż masz oczekiwania względem kodu. A dziura w szelkach bezpieczeństwa to szansa na niechcianą zmianę, która może zaszkodzić systemowi produkcyjnemu.

Timothy Truckle
źródło
2

Absolutnie tak. Byłem SDET dla dużej firmy programistycznej. Nasz mały zespół musiał utrzymywać kod testowy, który był obsługiwany przez znacznie większy zespół. Co więcej, nasz produkt miał pewne zależności, które stale wprowadzały przełomowe zmiany, co oznacza dla nas stałą konserwację testów. Nie mieliśmy możliwości zwiększenia liczebności zespołu, więc musieliśmy wyrzucić tysiące mniej wartościowych testów, gdy zawiodły. W przeciwnym razie nigdy nie bylibyśmy w stanie nadążyć za wadami.

Zanim odrzucisz to jako zwykły problem z zarządzaniem, zastanów się, że wiele projektów w realnym świecie cierpi z powodu zmniejszonej liczby pracowników, gdy zbliżają się do statusu starszego typu. Czasami zaczyna się nawet dziać zaraz po pierwszym wydaniu.

mrog
źródło
4
„Ponadto nasz produkt miał pewne zależności, które nieustannie wprowadzały przełomowe zmiany, co oznacza dla nas ciągłą konserwację testów”. - Testy, o których mówisz, że wymagają konserwacji, brzmią jak wartościowe, jeśli twoje zależności ciągle się psują.
CodeMonkey
2
To nie jest problem z testami, ale z organizacją.
jwenting
2
@CodeMonkey Zależności nie uległy awarii. Były one aktualizowane w sposób wymagający zmian w naszym produkcie. Tak, testy były cenne, ale nie tak cenne jak inne. Testy automatyczne są najcenniejsze, gdy równoważny test ręczny jest trudny.
mrog
2
@jwenting Tak, to problem organizacyjny, a nie problem z kodem. Ale to nie zmienia faktu, że było zbyt wiele testów. Niepowodzenie testu, którego nie można zbadać, jest bezużyteczne, niezależnie od przyczyny.
mrog
Co to jest „SDET”?
Peter Mortensen
1

Posiadanie większej liczby wierszy kodu testowego niż kodu produktu niekoniecznie stanowi problem, zakładając, że refaktoryzujesz kod testowy, aby wyeliminować kopiowanie-wklejanie.

Problemem są testy, które są odzwierciedleniem twojej implementacji, bez żadnego znaczenia biznesowego - na przykład testy załadowane próbnymi i pośredniczącymi kodami, a jedynie stwierdzenie, że metoda wywołuje inną metodę.

Wielkim cytatem w artykule „dlaczego większość testów jednostkowych jest marnotrawstwem” jest to, że testy jednostkowe powinny mieć „szeroką, formalną, niezależną wyrocznię poprawności i… możliwą do przypisania wartość biznesową”

wrschneider
źródło
0

Jednej rzeczy, o której nie wspomniałem, to to, że testy muszą być szybkie i łatwe, aby każdy programista mógł je uruchomić w dowolnym momencie.

Nie chcesz się zameldować w celu kontroli źródła i odczekać godzinę lub dłużej (w zależności od rozmiaru bazy kodu), zanim testy zakończą się, aby sprawdzić, czy twoja zmiana coś zepsuła - chcesz to zrobić na własny komputer przed zalogowaniem się do kontroli źródła (a przynajmniej przed wprowadzeniem zmian). Idealnie byłoby, gdybyś mógł uruchomić swoje testy za pomocą jednego skryptu lub naciśnięcia przycisku.

A kiedy uruchamiasz te testy lokalnie, chcesz, aby działały szybko - rzędu sekund. Jakikolwiek wolniejszy, a będziesz miał ochotę nie uruchomić ich wystarczająco dużo lub wcale.

Tak więc posiadanie tak wielu testów, że uruchomienie ich wszystkich zajmuje kilka minut lub kilka zbyt skomplikowanych testów, może stanowić problem.

mmathis
źródło