Dlaczego testy jednostkowe nie są postrzegane jako złe?

93

Najwyraźniej w niektórych organizacjach częścią procesu wydawania oprogramowania jest testowanie jednostkowe, ale w dowolnym momencie wszystkie testy jednostkowe muszą przejść pomyślnie. Np. Może być jakiś ekran, który pokazuje wszystkie testy jednostkowe przechodzące na zielono - co powinno być dobre.

Osobiście uważam, że tak nie powinno być z następujących powodów:

  1. Promuje ideę, że kod powinien być idealny i nie powinny istnieć żadne błędy - co w prawdziwym świecie jest z pewnością niemożliwe dla programu dowolnej wielkości.

  2. Odradza się wymyślanie testów jednostkowych, które się nie powiodą. Lub z pewnością wymyślą testy jednostkowe, które byłyby trudne do naprawienia.

  3. Jeśli w dowolnym momencie wszystkie testy jednostkowe zakończą się pomyślnie, nie ma dużego obrazu stanu oprogramowania w żadnym momencie. Nie ma mapy drogowej / celu.

  4. Odstrasza pisanie testów jednostkowych z góry - przed wdrożeniem.

Sugerowałbym nawet, że nawet wydanie oprogramowania z nieudanymi testami jednostkowymi nie jest konieczne. Przynajmniej wtedy wiesz, że niektóre aspekty oprogramowania mają ograniczenia.

Czy coś mi umyka? Dlaczego organizacje oczekują pozytywnego wyniku wszystkich testów jednostkowych? Czy to nie życie w świecie snów? I czy tak naprawdę nie przeszkadza to w prawdziwym zrozumieniu kodu?

użytkownik619818
źródło
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
wałek klonowy

Odpowiedzi:

270

To pytanie zawiera kilka nieporozumień, ale najważniejsze, na którym chciałbym się skupić, to to, że nie rozróżnia gałęzi rozwoju lokalnego, gałęzi trunk, inscenizacji lub wydania.

W lokalnym oddziale deweloperskim może się zdarzyć, że w dowolnym momencie przeprowadzą niektóre testy jednostkowe. W bagażniku jest do pewnego stopnia akceptowalny, ale już silny wskaźnik, aby naprawić rzeczy JAK NAJSZYBCIEJ. Pamiętaj, że nieudane testy jednostkowe w bagażniku mogą przeszkadzać reszcie zespołu, ponieważ wymagają od wszystkich sprawdzenia, czy nie jego ostatnia zmiana spowodowała awarię.

W gałęzi pomostowej lub zwalniającej testy zakończone niepowodzeniem są „czerwonym alarmem”, wskazując, że zniknęło coś zupełnie nie tak z jakimś zestawem zmian, gdy został on scalony z pnia do gałęzi zwalniającej.

Sugerowałbym nawet, że nawet wydanie oprogramowania z nieudanymi testami jednostkowymi nie jest konieczne.

Wydanie oprogramowania z pewnymi znanymi błędami poniżej określonego poziomu nie musi być złe. Te znane usterki nie powinny jednak powodować niepowodzenia testu jednostkowego. W przeciwnym razie, po każdym uruchomieniu testu jednostkowego, trzeba będzie sprawdzić 20 nieudanych testów jednostkowych i sprawdzić jeden po drugim, czy awaria była dopuszczalna, czy nie. To staje się kłopotliwe, podatne na błędy i odrzuca ogromną część aspektu automatyzacji testów jednostkowych.

Jeśli naprawdę masz testy na akceptowalne, znane błędy, skorzystaj z funkcji wyłączania / ignorowania narzędzia do testowania jednostek (aby nie były uruchamiane domyślnie, tylko na żądanie). Dodatkowo dodaj bilet o niskim priorytecie do narzędzia do śledzenia problemów, aby problem nie został zapomniany.

Doktor Brown
źródło
18
Myślę, że to jest prawdziwa odpowiedź. OP wspomina o „procesie wydania” i „pewnym ekranie [pokazującym wyniki testu]”, który brzmi jak serwer kompilacji. Wydanie to nie to samo, co programowanie (nie rozwijaj się w produkcji!); dobrze jest mieć nieudane testy w dev, są jak TODO; wszystkie powinny być zielone (GOTOWE) po przekazaniu do serwera kompilacji.
Warbo
7
O wiele lepsza odpowiedź niż najwyżej oceniona. Pokazuje zrozumienie, skąd pochodzi operacja, nie pouczając ich o idealnej sytuacji na świecie, uznaje możliwość znanych błędów (dla których nie odrzucono całej mapy drogowej, aby naprawić rzadkie przypadki na rogu) i wyjaśnia, że ​​testy jednostkowe powinny tylko zdecydowanie być zielony w gałęzi / procesie wydania.
Sebastiaan van den Broek
5
@SebastiaanvandenBroek: dziękuję za pozytywną odpowiedź. Żeby było jasne: testy jednostkowe z błędami IMHO powinny być rzadkie nawet w bagażniku, ponieważ zbyt częste występowanie takich awarii zakłóci cały zespół, a nie tylko tego, który dokonał zmiany, która spowodowała awarię.
Doc Brown
4
Myślę, że problemem tutaj jest myślenie, że wszystkie testy automatyczne są testami jednostkowymi. Wiele frameworków testowych obejmuje możliwość oznaczania testów, które mogą się nie powieść (często nazywane XFAIL). (Różni się to od testu wymagającego wyniku błędu. Testy XFAIL idealnie by się udały, ale nie.) Zestaw testów nadal przechodzi z tymi niepowodzeniami. Najczęstszym przypadkiem użycia są rzeczy, które zawodzą tylko na niektórych platformach (i tylko XFAIL na tych), ale użycie tej funkcji do śledzenia czegoś, co wymaga zbyt wiele pracy, aby naprawić w tej chwili, jest również uzasadnione. Ale tego rodzaju testy zwykle nie są testami jednostkowymi.
Kevin Cathcart
1
+1, chociaż sugeruję nieznaczne dodanie (pogrubioną czcionką) do tego zdania: „To staje się nieporęczne, podatne na błędy, powoduje, że ludzie ignorują awarie w zestawie testów jako hałas i odrzuca ogromną część aspektu automatyzacji testów jednostkowych ,
mtraceur
228

... wszystkie testy jednostkowe przechodzą na zielono - co powinno być dobre.

To jest dobre. Nie ma w tym „być”.

Promuje ideę, że kod powinien być idealny i nie powinny istnieć żadne błędy - co w prawdziwym świecie jest z pewnością niemożliwe dla programu dowolnej wielkości.

Nie. Dowodzi to, że przetestowałeś kod tak dobrze, jak możesz. Jest całkiem możliwe, że twoje testy nie obejmują wszystkich przypadków. Jeśli tak, ewentualne błędy pojawią się w raportach o błędach, a ty napiszesz [nieudane] testy w celu odtworzenia problemów, a następnie naprawisz aplikację tak, aby testy zakończyły się pomyślnie.

Odradza się wymyślanie testów jednostkowych, które się nie powiodą.

Niepowodzenie lub negatywne testy nakładają twarde ograniczenia na to, co Twoja aplikacja zaakceptuje i nie zaakceptuje. Większość programów, które znam, sprzeciwi się „dacie” 30 lutego. Ponadto programiści, którymi jesteśmy kreatywni, nie chcą łamać „swoich dzieci”. Koncentracja na przypadkach „szczęśliwej ścieżki” prowadzi do kruchych aplikacji, które często się psują.

Aby porównać sposób myślenia programisty i testera:

  • Deweloper zatrzymuje się, gdy tylko kod zrobi to, co chce.
  • Tester zatrzymuje się, gdy nie może już złamać kodu.

Są to radykalnie różne perspektywy, które trudno jest pogodzić wielu programistom.

Lub z pewnością wymyślą testy jednostkowe, które byłyby trudne do naprawienia.

Nie piszesz testów, aby pracować dla siebie. Piszesz testy, aby upewnić się, że Twój kod robi to, co powinien, a co ważniejsze, że nadal robi to, co powinien, po zmianie wewnętrznej implementacji.

  • Debugowanie „dowodzi”, że kod robi to, co chcesz dzisiaj .
  • Testy „dowodzą”, że kod nadal robi to, co chcesz, z czasem .

Jeśli w dowolnym momencie wszystkie testy jednostkowe zakończą się pomyślnie, nie ma dużego obrazu stanu oprogramowania w żadnym momencie. Nie ma mapy drogowej / celu.

Jedynym testem „obrazkowym” jest migawka, w której kod „działa” w momencie, w którym został przetestowany. Jak ewoluuje potem, to inna historia.

Odstrasza pisanie testów jednostkowych z góry - przed wdrożeniem.

Właśnie to powinieneś robić. Napisz test, który się nie powiedzie (ponieważ metoda, którą testuje, nie został jeszcze zaimplementowany), a następnie napisz kod metody, aby metoda zadziałała, a tym samym pozytywny wynik testu. To właściwie sedno rozwoju opartego na testach.

Sugerowałbym nawet, że nawet wydanie oprogramowania z nieudanymi testami jednostkowymi nie jest konieczne. Przynajmniej wtedy wiesz, że niektóre aspekty oprogramowania mają ograniczenia.

Zwolnienie kodu z uszkodzonymi testami oznacza, że ​​część jego funkcjonalności nie działa już tak jak wcześniej. Może to być celowe działanie, ponieważ naprawiłeś błąd lub ulepszyłeś funkcję (ale najpierw powinieneś zmienić test, aby się nie powiódł, a następnie zakodować poprawkę / ulepszenie, aby test działał w tym procesie). Co ważniejsze: wszyscy jesteśmy ludźmi i popełniamy błędy. Jeśli złamiesz kod, powinieneś przerwać testy, a te zepsute testy powinny ustawić dzwonienie dzwonków alarmowych.

Czy to nie życie w świecie snów?

Jeśli już, to żyje w świecie rzeczywistym , uznając, że deweloperzy nie są ani wszechwiedzący, ani infallable, że możemy zrobić, popełniają błędy i że potrzebujemy siatki bezpieczeństwa złapać nas, czy i kiedy zrobić bałagan!
Wprowadź testy.

I czy tak naprawdę nie przeszkadza to w prawdziwym zrozumieniu kodu?

Być może. Niekoniecznie musisz rozumieć implementację czegoś, aby napisać testy na to (to jest ich sedno). Testy określają zachowanie i ograniczenia aplikacji i zapewniają, że pozostają one takie same, chyba że celowo je zmienisz.

Phill W.
źródło
7
@ Tibos: Wyłączenie testu jest jak komentowanie funkcji. Masz kontrolę wersji. Użyj tego.
Kevin
6
@Kevin Nie wiem, co masz na myśli, mówiąc „użyj”. Oznaczam test jako „pomijany” lub „oczekujący” lub inną konwencję, z której korzysta mój tester, i przypisuję ten znacznik pominięcia do kontroli wersji.
dcorking
4
@orkorking: Mam na myśli, nie komentuj kodu, usuń go. Jeśli później zdecydujesz, że go potrzebujesz, przywróć go z kontroli wersji. Przeprowadzenie testu wyłączonego nie różni się.
Kevin
4
„Jest całkiem możliwe, że twoje testy nie obejmują wszystkich przypadków”. Chciałbym posunąć się tak daleko do stwierdzenia, że ​​dla każdego nietrywialnego kawałka testowanego kodu na pewno nie obejmuje się wszystkich przypadków.
corsiKa
6
@Tibos Zwolennicy testów jednostkowych twierdzą, że czas cyklu od napisania testu zakończonego niepowodzeniem do napisania odpowiedniego kodu powinien być mały (np. 20 minut. Niektórzy twierdzą, że 30 sekund). Jeśli nie masz czasu na napisanie kodu od razu, jest to prawdopodobnie zbyt skomplikowane. Jeśli nie jest to skomplikowane, usuń test, ponieważ można go przepisać, jeśli upuszczona funkcja zostanie ponownie dodana. Dlaczego nie skomentować? Nie wiesz, że ta funkcja zostanie ponownie dodana, więc skomentowany test (lub kod) to po prostu szum.
CJ Dennis
32

Dlaczego testy jednostkowe nie są postrzegane jako złe?

Nie są - rozwój oparty na testach opiera się na pojęciu testów zakończonych niepowodzeniem. Niepowodzenie testów jednostkowych prowadzących do rozwoju, niepowodzenie testów akceptacyjnych do prowadzenia historii ....

Brakuje kontekstu ; gdzie testy jednostkowe mogą się nie powieść?

Zazwyczaj odpowiedź jest taka, że ​​testy jednostkowe mogą się nie powieść tylko w prywatnych obszarach izolowanych.

Podstawowa koncepcja jest następująca: w środowisku, w którym dzielone są testy zakończone niepowodzeniem, dodatkowy wysiłek wymaga zrozumienia, czy zmiana kodu produkcyjnego spowodowała nowy błąd. Różnica między zero a nie zero jest znacznie łatwiejsza do wykrycia i zarządzania niż różnica między N a N.

Ponadto utrzymywanie kodu współdzielonego w czystości oznacza, że ​​programiści mogą pozostać przy zadaniu. Kiedy scalam twój kod, nie muszę zmieniać kontekstów od problemu, za który płacę mi rozwiązanie, do skalowania mojego zrozumienia, ile testów powinno się nie udać. Jeśli wspólny kod przechodzi wszystkie testy, wszelkie awarie pojawiające się podczas scalania moich zmian muszą być częścią interakcji między moim kodem a istniejącą czystą linią bazową.

Podobnie podczas wprowadzania na pokład nowy programista może szybciej zwiększyć produktywność, ponieważ nie musi tracić czasu na odkrywanie, które testy negatywne są „dopuszczalne”.

Mówiąc ściślej: dyscyplina polega na tym, że testy przeprowadzane podczas kompilacji muszą przejść pomyślnie.

Jak mogę powiedzieć, nie ma nic złego w wyłączaniu nieudanych testów .

Na przykład w środowisku „ciągłej integracji” będziesz dzielić się kodem z dużą częstotliwością. Często integracja niekoniecznie oznacza, że ​​zmiany muszą być gotowe do wydania. Istnieje szereg ciemnych technik wdrażania, które zapobiegają uwalnianiu ruchu do sekcji kodu, dopóki nie będą gotowe.

Te same techniki można również wykorzystać do wyłączenia testów zakończonych niepowodzeniem.

Jednym z ćwiczeń, które przeszedłem po wydaniu punktu, było opracowanie produktu z wieloma nieudanymi testami. Odpowiedzią, którą wymyśliliśmy, było po prostu przejrzenie pakietu, wyłączenie nieudanych testów i udokumentowanie każdego z nich. To pozwoliło nam szybko dotrzeć do punktu, w którym wszystkie włączone testy przeszły, a zarząd / darczyńca / właściciel złota mogli zobaczyć wszystkie transakcje, które podjęliśmy, aby dojść do tego punktu, i mogli podejmować świadome decyzje o oczyszczeniu a nowej pracy.

W skrócie: istnieją inne techniki śledzenia pracy, które nie zostały wykonane, niż pozostawienie szeregu nieudanych testów w uruchomionym pakiecie.

VoiceOfUnreason
źródło
Powiedziałbym: „Nie ma… nic złego w niepowodzeniu testów, które wyłączone ”.
CJ Dennis
Ta zmiana z pewnością wyjaśnia znaczenie. Dziękuję Ci.
VoiceOfUnreason
26

Istnieje wiele świetnych odpowiedzi, ale chciałbym dodać jeszcze jeden punkt, który moim zdaniem nie jest jeszcze dobrze opisany: jaki jest sens przeprowadzania testów.

Testy jednostkowe nie służą sprawdzeniu, czy Twój kod nie zawiera błędów.

Myślę, że to jest główne nieporozumienie. Gdyby to była ich rola, rzeczywiście można by się spodziewać, że w każdym miejscu będą mieć niepomyślne testy. Lecz,

Testy jednostkowe sprawdzają, czy Twój kod działa tak, jak myślisz.

W skrajnych przypadkach może to obejmować sprawdzenie, czy znane błędy nie zostały naprawione. Chodzi o to, aby mieć kontrolę nad bazą kodu i unikać przypadkowych zmian. Po dokonaniu zmiany wszystko jest w porządku i spodziewane jest przerwanie niektórych testów - zmieniasz zachowanie kodu. Świeżo zepsuty test to teraz dobry ślad tego, co zmieniłeś. Sprawdź, czy wszystkie pęknięcia są zgodne z tym, czego oczekujesz od zmiany. Jeśli tak, po prostu zaktualizuj testy i kontynuuj. Jeśli nie - no cóż, twój nowy kod jest zdecydowanie wadliwy, wróć i napraw go przed przesłaniem!

Teraz wszystkie powyższe działania działają tylko wtedy, gdy wszystkie testy są zielone, co daje mocne pozytywne wyniki: dokładnie tak działa kod. Czerwone testy nie mają tej właściwości. „Tego nie robi ten kod” rzadko jest użyteczną informacją.

Testy akceptacyjne mogą być tym, czego szukasz.

Istnieje coś takiego jak test akceptacyjny. Możesz napisać zestaw testów, które należy spełnić, aby wywołać kolejny kamień milowy. Mogą być czerwone, ponieważ do tego właśnie zostały zaprojektowane. Ale są one bardzo różne od testów jednostkowych i nie mogą ani nie powinny ich zastąpić.

Frax
źródło
2
Kiedyś musiałem wymienić bibliotekę na inną. Testy jednostkowe pomogły mi upewnić się, że wszystkie przypadki narożne były nadal traktowane identycznie przez nowy kod.
Thorbjørn Ravn Andersen
24

Widzę to jako programowy odpowiednik zespołu rozbitego okna .

Testy robocze mówią mi, że kod ma określoną jakość i że właściciele kodu dbają o to.

Jeśli chodzi o to, kiedy powinieneś dbać o jakość, zależy to raczej od gałęzi / repozytorium kodu źródłowego, nad którym pracujesz. Kod deweloperski mógł mieć bardzo zepsute testy wskazujące na trwające prace (miejmy nadzieję!).

Zepsute testy w oddziale / repozytorium dla systemu na żywo powinny natychmiast ustawić dzwonienie dzwonków alarmowych. Jeśli zepsute testy mogą nadal kończyć się niepowodzeniem lub jeśli są trwale oznaczone jako „zignoruj” - spodziewaj się, że ich liczba z czasem się powiększy. Jeśli nie będą one regularnie sprawdzane, zostanie ustawiony precedens, że pozostawienie uszkodzonych testów jest w porządku.

Zepsute testy są tak pejoratywnie oglądane w wielu sklepach, że mają ograniczenia co do tego, czy uszkodzony kod może być nawet popełniony .

Robbie Dee
źródło
9
Jeśli testy udokumentują sposób działania systemu, z pewnością powinny zawsze przechodzić - jeśli tak nie jest, oznacza to, że niezmienniki są zepsute. Ale jeśli udokumentują sposób, w jaki powinien być system, mogą też mieć zastosowanie testy nieudane - o ile struktura testów jednostkowych obsługuje dobry sposób oznaczania ich jako „znanych problemów” i łączenia ich z elementem w narzędziu do śledzenia problemów. Myślę, że oba podejścia mają swoje zalety.
Luaan
1
@Luaan Tak, to raczej zakłada, że ​​wszystkie testy jednostkowe są tworzone jednakowo. Z pewnością nie jest rzadkością, że menedżerowie kompilacji kroją i kroją testy za pomocą jakiegoś atrybutu, w zależności od tego, jak długo działają, jak kruche są i różnych innych kryteriów.
Robbie Dee
Ta odpowiedź jest świetna z mojego własnego doświadczenia. Gdy niektórzy ludzie przyzwyczają się do ignorowania szeregu nieudanych testów lub do złamania najlepszych praktyk w niektórych punktach, poczekaj kilka miesięcy, a zobaczysz, że% ignorowanych testów dramatycznie rośnie, a jakość kodu spada do poziomu „hack-script” . I bardzo trudno będzie przywołać wszystkich do procesu.
usr-local-ΕΨΗΕΛΩΝ
11

Oto podstawowy logiczny błąd:

Jeśli dobrze jest, gdy wszystkie testy zakończą się pomyślnie, musi być źle, jeśli którykolwiek z testów zakończy się niepowodzeniem.

Dzięki testom jednostkowym dobrze jest, gdy wszystkie testy przejdą pomyślnie. Jest również DOBRY, gdy test się nie powiedzie. Obaj nie muszą być w opozycji.

Niepowodzenie testu to problem, który został złapany przez twoje narzędzie zanim dotarł do użytkownika. To okazja, aby naprawić błąd przed opublikowaniem. I to dobrze.

Joel Coehoorn
źródło
Ciekawa myśl. Widzę błędność pytania bardziej w ten sposób: „ponieważ dobrze jest, gdy test jednostkowy się nie powiedzie, źle jest, gdy wszystkie testy przejdą”.
Doc Brown
Chociaż ostatni akapit jest dobrym punktem, wydaje się, że problemem jest raczej nieporozumienie „w dowolnym momencie wszystkie testy jednostkowe muszą przejść” (jak wskazuje zaakceptowana odpowiedź) i punkt testów jednostkowych.
Dukeling
9

Odpowiedź Phill W. jest świetna. Nie mogę tego zastąpić.

Chcę jednak skupić się na innej części, która mogła być częścią zamieszania.

Najwyraźniej w niektórych organizacjach częścią procesu wydawania oprogramowania jest testowanie jednostkowe, ale w dowolnym momencie wszystkie testy jednostkowe muszą przejść pomyślnie

„w dowolnym momencie” przesadza z twoją sprawą. Co ważne, testy jednostkowe przechodzą po wprowadzeniu pewnej zmiany, zanim zaczniesz wdrażać kolejną zmianę.
W ten sposób możesz śledzić, która zmiana spowodowała błąd. Jeśli testy jednostkowe rozpoczęły się niepowodzeniem po wdrożeniu zmiany 25, ale przed wdrożeniem zmiany 26, oznacza to, że zmiana 25 spowodowała błąd.

Oczywiście podczas wdrażania zmiany testy jednostkowe mogą się nie powieść; tat bardzo zależy od tego, jak duża jest zmiana. Jeśli przebudowuję podstawową funkcję, która jest czymś więcej niż drobną poprawką, prawdopodobnie przerwie testy na jakiś czas, dopóki nie skończę implementować mojej nowej wersji logiki.


Może to powodować konflikty dotyczące zasad zespołu. Tak naprawdę spotkałem to kilka tygodni temu:

  • Każde zatwierdzenie / wypchnięcie powoduje kompilację. Kompilacja nigdy nie może zakończyć się niepowodzeniem (jeśli to się powiedzie lub test zakończy się niepowodzeniem, winny jest programista zatwierdzający).
  • Oczekuje się, że każdy programista wprowadzi zmiany (nawet jeśli są niekompletne) pod koniec dnia, aby liderzy zespołu mogli sprawdzić kod rano.

Każda reguła byłaby w porządku. Ale obie zasady nie mogą ze sobą współpracować. Jeśli przydzielono mi poważną zmianę, której ukończenie zajmuje kilka dni, nie byłbym w stanie przestrzegać obu zasad jednocześnie. Chyba że będę komentował moje zmiany każdego dnia i dopuściłbym się ich bez komentarza po tym, jak wszystko zostało zrobione; która jest po prostu nonsensowną pracą.

W tym scenariuszu problemem nie jest to, że testy jednostkowe nie mają żadnego celu; to, że firma ma nierealne oczekiwania . Ich arbitralny zestaw reguł nie obejmuje wszystkich przypadków, a nieprzestrzeganie reguł jest ślepo uważane za awarię programisty, a nie za regułę (co w moim przypadku jest).

Flater
źródło
3
Jednym ze sposobów, w jaki to może działać, jest użycie rozgałęzienia, takiego jak devs commit i push, aby wyróżnić gałęzie, które nie muszą budować czysto, chociaż są niekompletne, ale zatwierdzenia do gałęzi rdzeniowej uruchamiają kompilację, która powinna budować czysto.
Gwyn Evans
1
Wymuszanie wprowadzania niepełnych zmian jest absurdalne, nie widzę żadnego uzasadnienia. Dlaczego nie sprawdzić kodu po zakończeniu zmiany?
Callum Bradbury,
Po pierwsze, jest to szybki sposób na upewnienie się, że kod znajduje się nie tylko na laptopie / stacji roboczej dewelopera, jeśli jego dysk twardy przestanie działać lub zostanie utracony w inny sposób - jeśli istnieje polityka zobowiązująca się nawet w trakcie pracy, to ryzyko jest ograniczone.
Gwyn Evans
1
Flagi cech naprawiają pozorny paradoks.
RubberDuck
1
@ Później tak, również do przeróbki istniejącej logiki.
RubberDuck
6

Jeśli nie naprawisz wszystkich testów jednostkowych, możesz szybko przejść do stanu, w którym nikt nie naprawia zepsutych testów.

  1. Jest niepoprawny, ponieważ testy jednostkowe nie wykazały, że kod jest idealny

  2. Odradzanie tworzenia kodu, który również byłby trudny do przetestowania, jest zniechęcające, co jest dobre z punktu widzenia projektu

  3. Pokrycie kodu może w tym pomóc (choć nie jest to panaceum). Również testy jednostkowe są tylko jednym aspektem testowania - chcesz również testy integracji / akceptacji.

jk.
źródło
6

Aby dodać kilka punktów do i tak dobrych odpowiedzi ...

ale w dowolnym momencie wszystkie testy jednostkowe muszą przejść pomyślnie

To pokazuje brak zrozumienia procesu wydania. Niepowodzenie testu może wskazywać na planowaną funkcję w TDD, która nie została jeszcze zaimplementowana; lub może wskazywać na znany problem, dla którego planowana jest poprawka dla przyszłej wersji; lub może to być po prostu coś, co zdaniem kierownictwa nie jest wystarczająco ważne, aby to naprawić, ponieważ klienci raczej tego nie zauważą. Kluczową rzeczą, jaką dzielą te wszystkie osoby, jest to, że kierownictwo dokonało osądu dotyczącego niepowodzenia.

Promuje ideę, że kod powinien być idealny i nie powinny istnieć żadne błędy - co w prawdziwym świecie jest z pewnością niemożliwe dla programu dowolnej wielkości.

Inne odpowiedzi obejmowały granice testowania.

Nie rozumiem jednak, dlaczego uważasz, że eliminowanie błędów jest wadą. Jeśli nie chcesz dostarczyć kodu, który sprawdziłeś (najlepiej jak potrafisz), robi to, co powinien, dlaczego nawet pracujesz w oprogramowaniu?

Jeśli w dowolnym momencie wszystkie testy jednostkowe zakończą się pomyślnie, nie ma dużego obrazu stanu oprogramowania w żadnym momencie. Nie ma mapy drogowej / celu.

Dlaczego musi istnieć plan działania?

Testy jednostkowe początkowo sprawdzają, czy funkcjonalność działa, ale następnie (jako testy regresyjne) sprawdzają, czy nie zostały przypadkowo uszkodzone. Dla wszystkich funkcji z istniejącymi testami jednostkowymi nie ma mapy drogowej . Każda funkcja działa (w granicach testowania). Jeśli ten kod jest gotowy, nie ma mapy drogowej, ponieważ nie trzeba więcej nad nim pracować.

Jako profesjonalni inżynierowie musimy unikać pułapki pozłacania. Hobbyści mogą sobie pozwolić na marnowanie czasu na majsterkowanie przy krawędziach z czymś, co działa. Jako profesjonaliści musimy dostarczyć produkt. Oznacza to, że dostajemy coś działającego, sprawdzamy, czy to działa, i przechodzimy do następnej pracy.

Graham
źródło
6

Promuje ideę, że kod powinien być idealny i nie powinny istnieć żadne błędy - co w prawdziwym świecie jest z pewnością niemożliwe dla programu dowolnej wielkości.

Nie prawda. dlaczego myślisz, że to niemożliwe? tutaj przykład dla programu, który działa:

public class MyProgram {
  public boolean alwaysTrue() {
    return true;
  }

  @Test
  public void testAlwaysTrue() {
    assert(alwaysTrue() == true);
  }
}

Odradza się wymyślanie testów jednostkowych, które się nie powiodą. Lub z pewnością wymyślą testy jednostkowe, które byłyby trudne do naprawienia.

W takim przypadku może to nie być test jednostkowy, ale test integracyjny, jeśli jest skomplikowany

Jeśli w dowolnym momencie wszystkie testy jednostkowe zakończą się pomyślnie, nie ma dużego obrazu stanu oprogramowania w żadnym momencie. Nie ma mapy drogowej / celu.

prawda, z jakiegoś powodu nazywa się to testem jednostkowym , sprawdza małą jednostkę kodu.

Odstrasza pisanie testów jednostkowych z góry - przed wdrożeniem.

Deweloperzy będziezniechęcać pisać żadnych testów, jeśli nie rozumieją jego zaletyz natury (chyba że pochodzą z kontroli jakości)

użytkownik7294900
źródło
„Deweloperzy będą zniechęcać do pisania testów ze swojej natury” - to kompletna bzdura. Pracuję w całej firmie programistów, którzy ćwiczą TDD i BDD.
RubberDuck
@RubberDuck Próbowałem odpowiedzieć na pytanie o „fakt” i przesadziłem. Zaktualizuję
użytkownik7294900
„X będzie odstraszać się od robienia Y, jeśli nie rozumieją korzyści Y” dotyczy prawie każdego X i Y, więc to stwierdzenie prawdopodobnie nie jest szczególnie przydatne. Prawdopodobnie bardziej sensowne byłoby wyjaśnienie korzyści z pisania testów, a zwłaszcza robienia tego z góry.
Dukeling
2
„niemożliwe dla programu o dowolnym rozmiarze” nie oznacza „wszystkich programów, bez względu na rozmiar”, oznacza „każdy znaczący program (mający nietrywialną długość)” Twój podany przykład nie jest odpowiedni, ponieważ nie jest znaczący i użyteczny program.
Ben Voigt
@BenVoigt Nie sądzę, że powinienem dać „znaczący program” jako odpowiedź.
user7294900
4

Promuje ideę, że kod powinien być idealny i nie powinny istnieć żadne błędy

Zdecydowanie nie. Promuje ideę, że twoje testy nie powinny zawieść, nic więcej i nic innego. Zakładanie, że przeprowadzanie testów (nawet wielu z nich) mówi coś o „doskonałym” lub „bez błędów”, jest błędem. Decydowanie o tym, jak płytkie lub głębokie powinny być twoje testy, stanowi znaczącą część pisania dobrych testów i powód, dla którego mamy wyraźnie oddzielne kategorie testów (testy „jednostkowe”, testy integracyjne, „scenariusze” w sensie ogórka itp.).

Odradza się wymyślanie testów jednostkowych, które się nie powiodą. Lub z pewnością wymyślą testy jednostkowe, które byłyby trudne do naprawienia.

W programowaniu opartym na testach obowiązkowe jest, aby wszystkie testy jednostkowe zakończyły się niepowodzeniem przed rozpoczęciem kodowania. Z tego właśnie powodu nazywa się to „cyklem czerwono-zielonym” (lub „cyklem refaktora czerwono-zielonego”).

  • Bez niepowodzenia testu nie wiadomo, czy kod jest faktycznie testowany przez test. Oba mogą w ogóle nie być powiązane.
  • Zmieniając kod, aby dokładnie zmienił kolor z czerwonego na zielony, nic więcej i nic więcej, możesz być całkiem pewny, że Twój kod robi to, co powinien, i niewiele więcej (czego może nigdy nie potrzebujesz).

Jeśli w dowolnym momencie wszystkie testy jednostkowe zakończą się pomyślnie, nie ma dużego obrazu stanu oprogramowania w żadnym momencie. Nie ma mapy drogowej / celu.

Testy są raczej rodzajem mikro-celu. W programowaniu opartym na testach programista najpierw napisze test (liczba pojedyncza), a następnie będzie miał wyraźny cel zaimplementowania kodu; następnie następny test i tak dalej.

Funkcja testów nie może być kompletna przed napisaniem kodu.

Wykonane poprawnie, w języku i przy użyciu biblioteki testowej, która jest dobrze dostosowana do tego podejścia, może faktycznie znacznie przyspieszyć programowanie, ponieważ komunikaty o błędach (wyjątki / ślady stosu) mogą bezpośrednio wskazywać deweloperowi, gdzie powinien wykonać pracę Kolejny.

Odstrasza pisanie testów jednostkowych z góry - przed wdrożeniem.

Nie rozumiem, jak to stwierdzenie byłoby prawdziwe. Testy pisemne powinny być idealnie częścią wdrożenia.

Czy coś mi umyka? Dlaczego organizacje oczekują pozytywnego wyniku wszystkich testów jednostkowych?

Ponieważ organizacje oczekują, że testy będą miały znaczenie dla kodu. Pomyślne napisanie testów oznacza, że ​​udokumentowałeś część aplikacji i udowodniłeś, że aplikacja wykonuje to, co mówi (test). Nic więcej i nic mniej.

Ponadto bardzo dużą częścią testów jest „regresja”. Chcesz mieć możliwość opracowywania lub refaktoryzacji nowego kodu z pewnością. Dzięki dużej ilości zielonych testów możesz to zrobić.

Od poziomu organizacyjnego do psychologicznego. Deweloper, który wie, że jego błędy najprawdopodobniej zostaną złapane przez testy, będzie mógł swobodniej wymyślić inteligentne, odważne rozwiązania problemów, które musi rozwiązać. Z drugiej strony programista, który nie ma testów, po pewnym czasie będzie się zatrzymywał (z powodu strachu), ponieważ nigdy nie wie, czy zmiana, którą robi, psuje resztę aplikacji.

Czy to nie życie w świecie snów?

Nie. Praca z aplikacją testowaną to czysta radość - chyba że nie podoba ci się ta koncepcja z jakiegokolwiek powodu („większy wysiłek” itp.), Który możemy omówić w innym pytaniu.

I czy tak naprawdę nie przeszkadza to w prawdziwym zrozumieniu kodu?

Absolutnie nie, dlaczego miałoby to być?

Znajdziesz wiele dużych projektów open source (dla których zarządzanie „zrozumieniem” i know-how na temat kodu jest bardzo palącym tematem), które faktycznie wykorzystują testy jako główną dokumentację oprogramowania, poza tym, że są testami, dostarczają również prawdziwe, działające, poprawne składniowo przykłady dla użytkowników lub programistów aplikacji / biblioteki. To często działa wspaniale.

Oczywiście pisanie złych testów jest złe. Ale to nie ma nic wspólnego z funkcją testów jako takich.

AnoE
źródło
3

(Z moich oryginalnych komentarzy)

Istnieje różnica między wymaganą funkcjonalnością a przyszłymi celami. Testy dotyczą wymaganej funkcjonalności: są precyzyjne, formalne, wykonywalne, a jeśli zawiodą, oprogramowanie nie działa. Przyszłe cele mogą nie być precyzyjne ani formalne, nie mówiąc już o wykonywalności, więc lepiej pozostawić je w języku naturalnym, np. W modułach do śledzenia problemów / błędów, dokumentacji, komentarzy itp.

W ramach ćwiczenia spróbuj zastąpić wyrażenie „test jednostkowy” w swoim pytaniu „błędem kompilatora” (lub „błędem składni”, jeśli nie ma kompilatora). Oczywiste jest, że wydanie nie powinno zawierać błędów kompilatora, ponieważ byłoby bezużyteczne; jednak błędy kompilatora i błędy składniowe są normalnym stanem rzeczy na komputerze programisty podczas pisania kodu. Błędy znikają dopiero po ich zakończeniu; i właśnie wtedy kod powinien zostać wypchnięty. Teraz zamień „błąd kompilatora” w tym akapicie na „test jednostkowy” :)

Warbo
źródło
2

Celem automatycznych testów jest jak najwcześniejsze poinformowanie cię, kiedy coś zepsułeś . Przepływ pracy wygląda trochę tak:

  1. Zmień coś
  2. Zbuduj i przetestuj swoją zmianę (najlepiej automatycznie)
  3. Jeśli testy się nie powiodą, oznacza to, że złamałeś coś, co wcześniej działało
  4. jeśli testy przejdą pomyślnie, należy mieć pewność, że zmiana nie wprowadziła żadnych nowych regresji (w zależności od zasięgu testu)

Jeśli Twoje testy już się nie powiodły, krok 3 nie działa tak skutecznie - testy zakończą się niepowodzeniem, ale nie wiesz, czy to oznacza, że ​​coś zepsułeś, czy nie, bez badania. Może możesz policzyć liczbę nieudanych testów, ale zmiana może naprawić jeden błąd i zepsuć inny, lub test może zakończyć się niepowodzeniem z innego powodu. Oznacza to, że musisz poczekać pewien czas, zanim dowiesz się, czy coś zostało zepsute, albo do momentu rozwiązania wszystkich problemów, albo do zbadania każdego niepowodzenia testu.

Zdolność testów jednostkowych do znalezienia nowo wprowadzonych błędów tak wcześnie, jak to możliwe, jest najcenniejszą rzeczą w automatycznych testach - im dłużej usterka pozostaje nieodkryta, tym droższa jest naprawa.

Promuje ideę, że kod powinien być idealny i nie powinny istnieć żadne błędy.
Odradza się wymyślanie testów jednostkowych, które zakończą się niepowodzeniem

Testy na rzeczy, które nie działają, nic ci nie mówią - napisz testy jednostkowe na rzeczy, które działają lub które masz zamiar naprawić. Nie oznacza to, że twoje oprogramowanie jest wolne od wad, oznacza to, że żadna z defektów, dla których wcześniej pisałeś testy jednostkowe, nie powróciła.

Odstrasza to pisanie testów jednostkowych z góry

Jeśli to działa, to napisz testy z góry, po prostu nie sprawdzaj ich w swoim systemie głównym, dopóki nie przejdą pomyślnie.

Jeśli w dowolnym momencie wszystkie testy jednostkowe zakończą się pomyślnie, nie ma dużego obrazu stanu oprogramowania w żadnym momencie. Nie ma mapy drogowej / celu.

Testy jednostkowe nie służą do ustalania mapy drogowej / celu, może zamiast tego użyć zaległości? Jeśli wszystkie testy zakończą się pomyślnie, „dużym obrazem” jest to, że oprogramowanie nie jest zepsute (jeśli zasięg testu jest dobry). Dobra robota!

Justin
źródło
2

Istniejące odpowiedzi są z pewnością dobre, ale nie widziałem, aby ktokolwiek zajął się tym fundamentalnym błędnym przekonaniem w pytaniu:

w dowolnym momencie wszystkie testy jednostkowe muszą zostać zaliczone

Nie. Z całą pewnością nie będzie to prawdą. Podczas tworzenia oprogramowania NCrunch jest najczęściej brązowy (błąd kompilacji) lub czerwony (test nieudany).

NCrunch musi być zielony (wszystkie testy przechodzą), kiedy jestem gotów wcisnąć zatwierdzenie do serwera kontroli źródła, ponieważ w tym momencie inni mogą polegać na moim kodzie.

To również stanowi wkład do tematu tworzenia nowych testów: testy powinny potwierdzać logikę i zachowanie kodu. Warunki brzegowe, warunki uszkodzenia itp. Pisząc nowe testy, próbuję zidentyfikować te „gorące punkty” w kodzie.

Testy jednostkowe dokumentują, jak mam się nazywać mój kod - warunki wstępne, oczekiwane wyniki itp.

Jeśli test ulegnie awarii po zmianie, muszę zdecydować, czy kod lub test jest w błędzie.


Na marginesie, testowanie jednostkowe czasami idzie w parze z testowaniem opartym na testach. Jedną z zasad TDD jest to, że zepsute testy są drogowskazami. Gdy test się nie powiedzie, musisz naprawić kod, aby test się powiódł. Oto konkretny przykład z początku tego tygodnia:

Tło : Napisałem i teraz obsługuję bibliotekę używaną przez naszych programistów, która służy do sprawdzania poprawności zapytań Oracle. Przeprowadziliśmy testy, które potwierdziły, że zapytanie odpowiada pewnej oczekiwanej wartości, co sprawiło, że wielkość liter była ważna (nie ma go w Oracle) i wesoło zaakceptowano nieprawidłowe zapytania, o ile całkowicie pasowały do ​​oczekiwanej wartości.

Zamiast tego moja biblioteka analizuje zapytanie, używając Antlr i składni Oracle 12c, a następnie opakowuje różne twierdzenia na samym drzewie składni. Rzeczy są poprawne (nie zgłoszono błędów analizy), wszystkie parametry są spełnione przez kolekcję parametrów, wszystkie oczekiwane kolumny odczytane przez czytnik danych są obecne w zapytaniu itp. Wszystkie są elementami, które prześlizgnęły się do produkcja w różnych momentach.

Jeden z moich kolegów inżynierów wysłał mi zapytanie w poniedziałek, które nie powiodło się (a raczej udało się, gdy powinno się nie powieść) w weekend. Moja biblioteka powiedziała, że ​​składnia jest dobra, ale wybuchła, gdy serwer próbował ją uruchomić. A kiedy spojrzał na zapytanie, było oczywiste, dlaczego:

UPDATE my_table(
SET column_1 = 'MyValue'
WHERE id_column = 123;

Załadowałem projekt i dodałem test jednostkowy, który stwierdził, że to zapytanie nie powinno być prawidłowe. Oczywiście test się nie powiódł.

Następnie ja debugowany test niepowodzeniem, przeszedł przez kod, gdzie oczekiwano go rzucić wyjątek i zorientowali się, że antlr było podniesienie błąd na otwartych paren, ale nie w taki sposób, poprzedni kod spodziewałem. Zmodyfikowałem kod, zweryfikowałem, że test był teraz zielony (pozytywny) i że nikt inny nie złamał się w tym procesie, nie zatwierdził i nie wypchnął.

Zajęło to może 20 minut, a proces znacznie poprawiłem bibliotekę, ponieważ teraz obsługiwał cały zakres błędów, które wcześniej ignorował. Gdybym nie miał testów jednostkowych dla biblioteki, badanie i rozwiązanie problemu zajęłoby wiele godzin.

GalacticCowboy
źródło
0

Jedna kwestia, która nie wydaje mi się wynikać z poprzednich odpowiedzi, polega na tym, że istnieje różnica między testami wewnętrznymi a testami zewnętrznymi (i myślę, że wiele projektów nie jest wystarczająco ostrożnych, aby je rozróżnić). Test wewnętrzny sprawdza, czy jakiś wewnętrzny element działa tak, jak powinien; zewnętrzny test pokazuje, że system jako całość działa tak, jak powinien. Oczywiście jest całkiem możliwe, że wystąpią awarie komponentów, które nie spowodują awarii systemu (być może istnieje funkcja komponentu, z której system nie korzysta, lub może system odzyskuje system po awarii składnik). Awaria komponentu, która nie skutkuje awarią systemu, nie powinna powstrzymywać Cię przed zwolnieniem.

Widziałem projekty sparaliżowane przez zbyt wiele testów komponentów wewnętrznych. Za każdym razem, gdy próbujesz wdrożyć ulepszenie wydajności, przerywasz dziesiątki testów, ponieważ zmieniasz zachowanie komponentów bez faktycznej zmiany widocznego z zewnątrz zachowania systemu. Prowadzi to do braku zwinności w całym projekcie. Uważam, że inwestycja w zewnętrzne testy systemu generalnie przynosi znacznie lepszą wypłatę niż inwestycja w wewnętrzne testy komponentów, szczególnie gdy mówimy o komponentach bardzo niskiego poziomu.

Kiedy sugerujesz, że nieudane testy jednostkowe tak naprawdę nie mają znaczenia, zastanawiam się, czy o to ci chodzi? Być może powinieneś oceniać wartość testów jednostkowych i porzucać te, które powodują więcej problemów niż są warte, jednocześnie koncentrując się bardziej na testach, które weryfikują widoczne z zewnątrz zachowanie aplikacji.

Michael Kay
źródło
Myślę, że to, co opisujesz jako „testy zewnętrzne”, jest często określane gdzie indziej jako „testy integracyjne”.
GalacticCowboy
Tak, ale natrafiłem na różnice terminologiczne. Dla niektórych osób testy integracyjne polegają bardziej na wdrożonej konfiguracji oprogramowania / sprzętu / sieci, natomiast mówię o zewnętrznym zachowaniu tworzonego oprogramowania.
Michael Kay
0

„ale w dowolnym momencie wszystkie testy jednostkowe muszą przejść pomyślnie”

Jeśli taka jest postawa w Twojej firmie, to jest problem. W PEWNYM czasie, kiedy deklarujemy, że kod jest gotowy do przejścia do następnego środowiska, wszystkie testy jednostkowe powinny przejść pomyślnie. Ale podczas opracowywania powinniśmy rutynowo oczekiwać, że wiele testów jednostkowych zakończy się niepowodzeniem.

Żadna rozsądna osoba nie oczekuje od programisty doskonałej pracy za pierwszym razem. Racjonalnie oczekujemy, że będzie nad tym pracował, dopóki nie będą znane żadne problemy.

„Odradzanie wymyślania testów jednostkowych, które zakończą się niepowodzeniem, jest zniechęcające. A na pewno wymyślenie testów jednostkowych, które trudno byłoby naprawić”. Jeśli ktoś w Twojej organizacji myśli, że nie powinien wspominać o możliwym teście, ponieważ może się on nie powieść i spowodować, że będzie musiał więcej pracy, aby go naprawić, osoba ta jest całkowicie niewykwalifikowana do swojej pracy. To katastrofalne podejście. Czy chciałbyś, żeby lekarz powiedział: „Kiedy robię operację, celowo nie sprawdzam, czy szwy są prawidłowe, ponieważ jeśli zobaczę, że nie są, będę musiał wrócić i wykonać je ponownie, i to zwolni zakończenie operacji ”?

Jeśli zespół jest wrogo nastawiony do programistów, którzy identyfikują błędy, zanim kod trafi do produkcji, masz poważny problem z postawą tego zespołu. Jeśli kierownictwo karze programistów, którzy identyfikują błędy spowalniające dostawę, istnieje prawdopodobieństwo, że Twoja firma zmierza w kierunku bankructwa.

Tak, to z pewnością prawda, że ​​czasami racjonalni ludzie mówią: „Zbliżamy się do terminu, to jest trywialny problem i nie warto poświęcać zasobów w tej chwili, aby to naprawić”. Ale nie możesz podjąć racjonalnej decyzji, jeśli nie wiesz. Chłodne sprawdzanie listy błędów i przypisywanie priorytetów i harmonogramów do ich naprawy jest racjonalne. Uświadomienie sobie, że nie jesteś świadomy problemów, abyś nie musiał podejmować tej decyzji, jest głupie. Czy uważasz, że klient nie dowie się tylko dlatego, że nie chcesz wiedzieć?

Sójka
źródło
-7

Jest to konkretny przykład uprzedzenia potwierdzającego , w którym ludzie szukają informacji, które potwierdzają ich istniejące przekonania.

Jednym ze znanych przykładów tego zjawiska jest gra 2,4,6.

  • Mam w głowie zasadę, że jakakolwiek seria trzech liczb przejdzie lub się nie powiedzie,
  • 2,4,6 to przepustka
  • możesz wymienić zestawy trzech liczb, a powiem ci, czy zdadzą, czy nie.

Większość ludzi wybiera regułę, mówiąc: „różnica między 1. a 2. numerem jest taka sama jak różnica między 2. a 3.”.

Przetestują niektóre liczby:

  • 4, 8, 12? Przechodzić
  • 20, 40, 60? Przechodzić
  • 2, 1004, 2006? Przechodzić

Mówią: „Tak, każda obserwacja potwierdza moją hipotezę, to musi być prawda”. I ogłosić swoją zasadę osobie, która rozwiązuje zagadkę.

Ale nigdy nie otrzymali ani jednego „niepowodzenia” żadnego zestawu trzech liczb. Zasadą może być po prostu „trzy liczby muszą być liczbami” dla wszystkich faktycznie posiadanych informacji.

Zasadą jest po prostu, że liczby są w porządku rosnącym. Ludzie zwykle rozwiązują tę zagadkę tylko wtedy, gdy testują na niepowodzenie. Większość ludzi myli się, wybierając bardziej szczegółową regułę i testując tylko liczby spełniające tę konkretną regułę.

Co do tego, dlaczego ludzie zakochują się w uprzedzeniach potwierdzających i mogą widzieć, że testy jednostkowe zawodzą jako dowód na problem, jest wielu psychologów, którzy mogą wyjaśnić uprzedzenia potwierdzające lepiej niż ja, w zasadzie sprowadza się to do osób, które nie lubią się mylić i próbują autentycznie próbować udowodnić, że się mylą.

Scott
źródło
2
Jak to ma znaczenie dla pytania? Nieudane testy jednostkowe z definicji dowodem problemu.
Frax
1
Państwo absolutnie może mieć testy jednostkowe, które wymagają systemu badanego wejścia w tryb awarii. To nie to samo, co nigdy nie widząc niepowodzenia testu. Właśnie dlatego TDD jest określony jako cykl „Czerwony-> Zielony-> Refaktor”
Caleth