Dlaczego warto używać JUnit do testowania?

131

Może moje pytanie jest dla początkujących, ale nie bardzo rozumiem okoliczności, w jakich bym użył ?

Niezależnie od tego, czy piszę proste aplikacje, czy większe, testuję je za pomocą System.outoświadczeń i wydaje mi się to całkiem łatwe.

Po co tworzyć klasy testowe z JUnitem, niepotrzebnymi folderami w projekcie, jeśli nadal musimy wywoływać te same metody, sprawdzać, co zwracają, a potem mamy narzut związany z dodawaniem adnotacji do wszystkiego?

Dlaczego nie napisać klasy i nie przetestować jej jednocześnie, System.outale nie utworzyć klas testowych?

PS. Nigdy nie pracowałem nad dużymi projektami, których dopiero się uczę.

Więc jaki jest cel?

Artem Moskalev
źródło
1
Przeczytaj sztukę testów jednostkowych
rgeorge
7
Czy zdajesz sobie sprawę, że za każdym razem, gdy zmieniasz cokolwiek w programie, cała Twoja poprzednia praca polegająca na ręcznym sprawdzaniu wyników jest unieważniana i musisz je powtarzać od początku?
Thorbjørn Ravn Andersen
Nie tylko „testowanie”, ale także „sprytne testowanie” jest bardzo ważne. Oto fajny przykład: wp.me/prMeE-11
akcasoy

Odpowiedzi:

140

To nie jest testowanie, to „ręczne przeglądanie wyników” (znane w biznesie jako LMAO). Bardziej formalnie jest to znane jako „ręczne wyszukiwanie nieprawidłowych wyników” (LMFAO). (Zobacz notkę poniżej)

Za każdym razem, gdy zmieniasz kod, musisz uruchomić aplikację i LMFAO dla całego kodu, na który mają wpływ te zmiany. Nawet w małych projektach jest to problematyczne i podatne na błędy.

Teraz skaluj do 50k, 250k, 1m LOC lub więcej i LMFAO za każdym razem, gdy wprowadzisz zmianę kodu. Nie tylko jest to nieprzyjemne, ale wręcz niemożliwe: przeskalowałeś kombinacje wejść, wyjść, flag, warunków i trudno jest ćwiczyć wszystkie możliwe gałęzie.

Co gorsza, LMFAO może oznaczać odwiedzanie stron na stronach aplikacji internetowej, generowanie raportów, przeglądanie milionów wierszy dziennika w dziesiątkach plików i maszyn, odczytywanie wygenerowanych i dostarczonych wiadomości e-mail, sprawdzanie wiadomości tekstowych, sprawdzanie ścieżki robota, napełnianie butelki soda, agregowanie danych ze stu serwisów internetowych, sprawdzanie ścieżki audytu transakcji finansowej ... masz pomysł. „Wyjście” nie oznacza kilku wierszy tekstu, „wyjście” oznacza zagregowane zachowanie systemu.

Wreszcie testy jednostkowe i behawioralne definiują zachowanie systemu. Testy mogą być uruchamiane przez serwer ciągłej integracji i sprawdzane pod kątem poprawności. Jasne, tak samo System.outjest, ale serwer CI nie będzie wiedział, czy któryś z nich jest zły - a jeśli tak, to są to testy jednostkowe i równie dobrze możesz użyć frameworka.

Bez względu na to, jak dobrzy nam się wydaje, ludzie nie są dobrymi strukturami testów jednostkowych ani serwerami CI.


Uwaga: LMAO jest testowanie, ale w bardzo ograniczonym sensie. Nie jest to powtarzalne w żaden znaczący sposób w całym projekcie lub jako część procesu. Jest to podobne do rozwijania przyrostowego w REPL, ale nigdy nie formalizowania tych testów przyrostowych.

Dave Newton
źródło
3
-1 dla pierwszego zdania, które jest całkowicie i całkowicie nieprawdziwe.
Michael Borgwardt,
50

Piszemy testy sprawdzające poprawność działania programu.

Weryfikacja poprawności działania programu poprzez sprawdzenie treści instrukcji wyjściowych za pomocą oczu jest procesem ręcznym , a dokładniej wizualnym .

Można się temu spierać

inspekcja wizualna działa , sprawdzam, czy kod robi to, co powinien, dla tych scenariuszy i kiedy widzę, że jest poprawny, możemy zaczynać.

Po pierwsze, świetnie, że jesteś zainteresowany tym, czy kod działa poprawnie. To dobra rzecz. Wyprzedzasz zakręt! Niestety, z takim podejściem są problemy.

Pierwszy problem z inspekcją wizualną polega na tym, że jesteś poważnym wypadkiem spawalniczym i nie możesz nigdy ponownie sprawdzić poprawności kodu.

Drugi problem polega na tym, że para oczu jest ściśle sprzężona z mózgiem właściciela oczu. Jeżeli autor kodu jest również właścicielem oczu wykorzystywanych w procesie oględzin, to proces weryfikacji poprawności jest uzależniony od wiedzy o programie zinternalizowanej w mózgu inspektora wizualnego.

Trudno jest wejść nowej parze oczu i zweryfikować poprawność kodu tylko dlatego, że nie współpracują z mózgiem oryginalnego programisty. Właściciel drugiej pary oczu będzie musiał porozmawiać z oryginalnym autorem kodu, aby w pełni zrozumieć dany kod. Rozmowa jako sposób dzielenia się wiedzą jest notorycznie zawodna. Kwestia dyskusyjna, jeśli oryginalny koder jest niedostępny dla nowej pary oczu. W takim przypadku nowa para oczu musi odczytać oryginalny kod.

Czytanie kodu innych osób, który nie jest objęty testami jednostkowymi, jest trudniejsze niż czytanie kodu, który ma skojarzone testy jednostkowe. W najlepszym przypadku czytanie kodu innych ludzi jest trudną pracą, w najgorszym jest to najbardziej natarczywe zadanie w inżynierii oprogramowania. Nie bez powodu pracodawcy, ogłaszając oferty pracy, podkreślają, że projekt jest od podstaw (lub zupełnie nowy). Pisanie kodu od podstaw jest łatwiejsze niż modyfikowanie istniejącego kodu, a tym samym sprawia, że ​​ogłoszone stanowisko wydaje się bardziej atrakcyjne dla potencjalnych pracowników.

Za pomocą testów jednostkowych dzielimy kod na części składowe. Dla każdego komponentu określamy następnie nasze stanowisko, określając, jak powinien zachowywać się program . Każdy test jednostkowy opowiada historię tego, jak ta część programu powinna działać w określonym scenariuszu. Każdy test jednostkowy jest jak klauzula w umowie, która opisuje, co powinno się stać z punktu widzenia kodu klienta.

Oznacza to, że nowa para oczu ma dwa pasma żywej i dokładnej dokumentacji dotyczącej danego kodu.

Najpierw mają sam kod, implementację, sposób wykonania kodu ; po drugie, mają całą wiedzę, którą pierwotny koder opisał w zestawie formalnych instrukcji, które opowiadają historię tego, jak ten kod ma się zachowywać.

Testy jednostkowe wychwytują i formalnie opisują wiedzę, jaką posiadał pierwotny autor, kiedy implementował klasę. Zawierają opis tego, jak ta klasa zachowuje się, gdy jest używana przez klienta.

Masz rację, kwestionując przydatność tego rozwiązania, ponieważ możliwe jest pisanie testów jednostkowych, które są bezużyteczne, nie obejmują całego kodu, stają się nieaktualne lub nieaktualne i tak dalej. W jaki sposób możemy zapewnić, że testy jednostkowe nie tylko naśladują, ale także usprawniają proces doświadczonego, sumiennego autora, który wizualnie sprawdza instrukcje wyjściowe swojego kodu w czasie wykonywania? Najpierw napisz test jednostkowy, a następnie napisz kod, aby ten test przeszedł pomyślnie. Kiedy skończysz, pozwól komputerom uruchomić testy, są szybkie, świetnie radzą sobie z powtarzającymi się zadaniami, idealnie nadają się do pracy.

Zapewnij jakość testów, przeglądając je za każdym razem, gdy wyłączasz testowany przez nie kod i uruchamiasz testy dla każdej kompilacji. Jeśli test się nie powiedzie, napraw go natychmiast.

Automatyzujemy proces uruchamiania testów tak, aby były uruchamiane za każdym razem, gdy budujemy projekt. Automatyzujemy również generowanie raportów pokrycia kodu, które szczegółowo opisują, jaki procent kodu jest pokryty i poddany testom. Dążymy do wysokich procentów. Niektóre firmy uniemożliwiają wprowadzanie zmian w kodzie do kontroli kodu źródłowego, jeśli nie mają napisanych wystarczających testów jednostkowych, aby opisać wszelkie zmiany w zachowaniu kodu. Zazwyczaj druga para oczu dokonuje przeglądu zmian w kodzie w połączeniu z autorem zmian. Recenzent przeprowadzi zmiany, upewniając się, że zmiany są zrozumiałe i dostatecznie objęte testami. Proces recenzji jest więc ręczny, ale gdy testy (testy jednostkowe i integracyjne oraz ewentualnie testy akceptacyjne użytkownika) przejdą ten ręczny proces przeglądu, stają się częścią automatycznego procesu kompilacji. Są one uruchamiane za każdym razem, gdy wprowadzana jest zmiana. A serwer wykonuje to zadanie jako część procesu budowania.

Testy, które są uruchamiane automatycznie, utrzymują integralność zachowania kodu i zapobiegają uszkodzeniu kodu przez przyszłe zmiany w bazie kodu .

Wreszcie, udostępnianie testów pozwala na agresywne ponowne fakturowanie kodu, ponieważ można bezpiecznie wprowadzać duże ulepszenia kodu, wiedząc, że zmiany nie przerywają istniejących testów.

Istnieje zastrzeżenie dotyczące programowania sterowanego testami, a mianowicie, że musisz pisać kod z myślą o umożliwieniu jego testowania. Obejmuje to kodowanie do interfejsów i używanie technik, takich jak Dependency Injection, w celu tworzenia instancji współpracujących obiektów. Sprawdź prace Kenta Becka, który bardzo dobrze opisuje TDD. Wyszukaj kodowanie w interfejsach i przestudiuj

Rob Kielty
źródło
13

Kiedy testujesz używając czegoś takiego jak System.out, testujesz tylko niewielki podzbiór możliwych przypadków użycia. Nie jest to zbyt dokładne, gdy masz do czynienia z systemami, które mogą przyjąć prawie nieskończoną liczbę różnych danych wejściowych.

Testy jednostkowe są zaprojektowane tak, aby umożliwić szybkie uruchamianie testów w aplikacji przy użyciu bardzo dużego i zróżnicowanego zestawu różnych danych wejściowych. Ponadto najlepsze testy jednostkowe uwzględniają również przypadki graniczne, takie jak dane wejściowe, które znajdują się na skraju tego, co jest uważane za prawidłowe.

Testowanie wszystkich tych różnych danych wejściowych przez człowieka może zająć tygodnie, podczas gdy maszyna może zająć minuty.

Pomyśl o tym w ten sposób: nie „testujesz” czegoś, co będzie statyczne. Twoja aplikacja najprawdopodobniej podlega ciągłym zmianom. W związku z tym te testy jednostkowe są przeznaczone do uruchamiania w różnych punktach cyklu kompilacji lub wdrażania. Być może największą zaletą jest to:

Jeśli coś zepsujesz w swoim kodzie, dowiesz się o tym teraz , a nie po wdrożeniu, a nie wtedy, gdy tester kontroli jakości wykryje błąd, a nie wtedy, gdy klienci anulują. Będziesz mieć również większą szansę na natychmiastowe naprawienie usterki , ponieważ jest jasne, że rzecz, która zepsuła część kodu, o którym mowa, najprawdopodobniej wydarzyła się od ostatniej kompilacji. W ten sposób ilość pracy dochodzeniowej potrzebnej do rozwiązania problemu jest znacznie zmniejszona.

jmort253
źródło
9

Dodałem kilka innych System.out NIE może zrobić:

  • Spraw, aby każdy przypadek testowy był niezależny (to ważne)

    JUnit może to zrobić: za każdym razem, gdy zostanie utworzona i @Beforewywołana nowa instancja przypadku testowego .

  • Oddzielny kod testowy od źródła

    JUnit może to zrobić.

  • Integracja z CI

    JUnit może to zrobić z Ant i Mavenem.

  • Z łatwością organizuj i łącz przypadki testowe

    JUnit może zrobić @Ignorei przetestować pakiet.

  • Łatwy do sprawdzenia wynik

    JUnit oferuje wiele metod Assert ( assertEquals, assertSame...)

  • Mock and stub sprawi, że skupisz się na module testowym.

    JUnit potrafi: Używając makiety i odgałęzienia, skonfigurować poprawne urządzenie i skupić się na logice modułu testowego.

卢 声 远 Shengyuan Lu
źródło
9

Testy jednostkowe zapewniają, że kod działa zgodnie z przeznaczeniem. Są również bardzo pomocne, aby upewnić się, że kod nadal działa zgodnie z przeznaczeniem na wypadek, gdybyś musiał go później zmienić, aby zbudować nowe funkcje i naprawić błąd. Posiadanie dużego pokrycia testowego kodu umożliwia dalsze rozwijanie funkcji bez konieczności wykonywania wielu testów ręcznych.

Twoje ręczne podejście System.outjest dobre, ale nie najlepsze. Jest to jednorazowy test, który wykonujesz. W prawdziwym świecie wymagania ciągle się zmieniają i przez większość czasu dokonujesz wielu modyfikacji istniejących funkcji i klas. Więc… nie za każdym razem, gdy testujesz już napisany fragment kodu.

są też bardziej zaawansowane funkcje, takie jak JUnit

Oświadczenia asercyjne

JUnit zapewnia metody do testowania pod pewnymi warunkami, metody te zwykle rozpoczynają się od potwierdzeń i pozwalają określić komunikat o błędzie, oczekiwany i rzeczywisty wynik

Niektóre z tych metod są

  1. fail([message])- Pozwala na niepowodzenie testu. Może być użyty do sprawdzenia, czy określona część kodu nie została osiągnięta. Lub nieudany test przed wdrożeniem kodu testowego.
  2. assertTrue(true)/ assertTrue(false)- zawsze będzie prawdziwe / fałszywe. Może być użyty do wstępnego zdefiniowania wyniku testu, jeśli test nie został jeszcze zaimplementowany.
  3. assertTrue([message,] condition)- Sprawdza, czy wartość logiczna conditionjest prawdziwa.
  4. assertEquals([message,] expected, actual)- Sprawdza, czy dwie wartości są równe (zgodnie z equalsmetodą, jeśli jest zaimplementowana, w przeciwnym razie przy użyciu ==porównania referencyjnego). Uwaga: W przypadku tablic sprawdzane jest odwołanie, a nie zawartość assertArrayEquals([message,] expected, actual).
  5. assertEquals([message,] expected, actual, delta)- Sprawdza, czy dwie wartości zmiennoprzecinkowe lub podwójne znajdują się w określonej odległości od siebie, kontrolowanej przez deltawartość.
  6. assertNull([message,] object) - Sprawdza, czy obiekt jest pusty

i tak dalej. Zobacz pełny Javadoc dla wszystkich przykładów tutaj .

Suites

Dzięki zestawom testów można w pewnym sensie łączyć wiele klas testowych w jedną jednostkę, aby można było wykonywać je wszystkie naraz. Prosty przykład, łączenie klas testowych MyClassTesti MySecondClassTestdo jednego pakietu o nazwie AllTests:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ MyClassTest.class, MySecondClassTest.class })
public class AllTests { } 
Arvind
źródło
6

Główną zaletą JUnit jest to, że jest on zautomatyzowany, a nie ręczne sprawdzanie wydruków. Każdy napisany przez ciebie test pozostaje w twoim systemie. Oznacza to, że jeśli wprowadzisz zmianę, która ma nieoczekiwany efekt uboczny, test wykryje ją i zakończy się niepowodzeniem, zamiast pamiętać o ręcznym testowaniu wszystkiego po każdej zmianie.

n00begon
źródło
4

JUnit to platforma do testów jednostkowych dla języka programowania Java. Jest to ważne w programowaniu opartym na testach i należy do rodziny frameworków do testów jednostkowych, zwanych łącznie xUnit.

JUnit promuje ideę „najpierw testowania, a następnie kodowania”, która kładzie nacisk na konfigurowanie danych testowych dla fragmentu kodu, który można najpierw przetestować, a następnie zaimplementować. To podejście przypomina „trochę przetestuj, trochę zakoduj, trochę przetestuj, trochę zakoduj ...”, co zwiększa produktywność programisty i stabilność kodu programu, co zmniejsza stres programisty i czas poświęcony na debugowanie.

Funkcje JUnit to framework open source, który jest używany do pisania i uruchamiania testów.

Zawiera adnotacje umożliwiające identyfikację metod testowych.

Zapewnia potwierdzenia do testowania oczekiwanych wyników.

Udostępnia programy uruchamiające testy do przeprowadzania testów.

Testy JUnit pozwalają na szybsze pisanie kodu, co zwiększa jakość

JUnit jest elegancko prosty. Jest mniej skomplikowany i zajmuje mniej czasu.

Testy JUnit mogą być uruchamiane automatycznie i sprawdzają własne wyniki i zapewniają natychmiastową informację zwrotną. Nie ma potrzeby ręcznego przeczesywania raportu wyników testu.

Testy JUnit można organizować w zestawy testów zawierające przypadki testowe, a nawet inne zestawy testów.

Junit pokazuje postęp testu na pasku, który jest zielony, jeśli test przebiega dobrze, a zmienia kolor na czerwony, gdy test się nie powiedzie.

AKKI
źródło
2

Mam nieco inną perspektywę, dlaczego JUnit jest potrzebny.

W rzeczywistości możesz sam napisać wszystkie przypadki testowe, ale jest to uciążliwe. Oto problemy:

  1. Zamiast tego System.outmożemy dodać if(value1.equals(value2))i zwrócić 0 lub -1 lub komunikat o błędzie. W tym przypadku potrzebujemy "głównej" klasy testowej, która uruchamia wszystkie te metody i sprawdza wyniki oraz utrzymuje, które przypadki testowe się nie powiodły, a które przeszły.

  2. Jeśli chcesz dodać więcej testów, musisz dodać je również do tej "głównej" klasy testowej. Zmiany w istniejącym kodzie. Jeśli chcesz automatycznie wykrywać przypadki testowe z klas testowych, musisz użyć odbicia.

  3. Wszystkie twoje testy i twoja główna klasa do uruchamiania testów nie są wykrywane przez eclipse i aby uruchomić te testy, musisz napisać niestandardowe konfiguracje debugowania / uruchamiania. Nadal jednak nie widać tych ładnych wyjść w kolorze zielonym / czerwonym.

Oto, co robi JUnit:

  1. Posiada assertXXX()metody, które są przydatne do drukowania pomocnych komunikatów o błędach z warunków i przekazywania wyników do klasy „main”.

  2. Klasa „main” nazywa się runner i jest dostarczana przez JUnit, więc nie musimy jej pisać. I automatycznie wykrywa metody testowe na podstawie refleksji. Jeśli dodasz nowe testy z @Testadnotacjami, zostaną one automatycznie wykryte.

  3. JUnit ma również integrację z eclipse i integracją maven / gradle, dzięki czemu można łatwo uruchamiać testy i nie trzeba pisać niestandardowych konfiguracji uruchamiania.

Nie jestem ekspertem w JUnit, więc to, co rozumiem na razie, doda więcej w przyszłości.

Sreekar
źródło
Wydaje mi się, że w pierwszej części napisałeś, co byśmy zrobili, gdyby nie było JUnita, aby testy jednostkowe były trochę lepsze niż instrukcje system.out.println. Być może JUnit jest wynikiem takich prób niektórych programistów i poczuli potrzebę napisania oddzielnego frameworka testowego do przeprowadzenia tej automatyzacji, a więc JUnit może się narodzić.
Saurabh Patil
1

Nie możesz napisać żadnego przypadku testowego bez korzystania z platformy testowej, bo inaczej będziesz musiał napisać ramkę testową, aby oddać sprawiedliwość swoim przypadkom testowym. Oto kilka informacji o JUnit Framework oprócz tego, że możesz użyć frameworka TestNG.

Co to jest Junit?

Junit to szeroko stosowany framework testowy wraz z językiem programowania Java. Możesz użyć tej struktury automatyzacji zarówno do testowania jednostkowego, jak i testowania interfejsu użytkownika, pomaga nam zdefiniować przepływ wykonywania naszego kodu za pomocą różnych adnotacji. Junit opiera się na idei „najpierw testowania, a następnie kodowania”, co pomaga nam zwiększyć produktywność przypadków testowych i stabilność kodu.

Ważne cechy testów Junit -

  1. Jest to platforma testowa typu open source, która umożliwia użytkownikom efektywne pisanie i uruchamianie przypadków testowych.
  2. Zapewnia różne typy adnotacji do identyfikacji metod testowych.
  3. Zapewnia różne typy twierdzeń do weryfikacji wyników wykonania przypadku testowego.
  4. Zapewnia również biegaczom testów do skutecznego przeprowadzania testów.
  5. Jest to bardzo proste i dzięki temu oszczędza czas.
  6. Zapewnia sposoby organizowania przypadków testowych w postaci zestawów testowych.
  7. Daje wyniki przypadków testowych w prosty i elegancki sposób.
  8. Możesz zintegrować jUnit z Eclipse, Android Studio, Maven & Ant, Gradle i Jenkins
anuja jain
źródło
0

JUNIT to metoda, która jest zwykle akceptowana przez programistów Java. Tam, gdzie mogą zapewnić podobne oczekiwane dane wejściowe do funkcji i odpowiednio zdecydować, że napisany kod jest doskonale napisany lub jeśli przypadek testowy się nie powiedzie, może być konieczne wdrożenie innego podejścia. JUNIT przyspieszy rozwój i zapewni 0 wad funkcji.

mohit sarsar
źródło
0

JUNIT: OBSERWUJ I DOSTOSUJ

Oto moja perspektywa JUNIT.

JUNIT może służyć do:
1) Obserwować zachowanie systemu, gdy do systemu zostanie dodana nowa jednostka.
2) Dokonaj regulacji w systemie, aby powitać „nową” jednostkę w systemie.
Co? Dokładnie.

Prawdziwe życie np.

Kiedy twój krewny odwiedza twój pokój w akademiku,
1) będziesz udawać, że jesteś bardziej odpowiedzialny.
2) Będziesz trzymać wszystko na swoim miejscu, np. Buty w półce na buty, a nie na krześle, ubrania w szafce, a nie na krześle.
3) Pozbędziesz się całej kontrabandy.
4) zaczniesz cleanUp na każdym posiadanym urządzeniu.

Pod względem programowania

System: Twój kod
UNIT: nowa funkcjonalność.
Ponieważ framework JUNIT jest używany w języku JAVA, więc JUNIT = JAVA UNIT (może być).

Załóżmy, że masz już dobry, kuloodporny kod, ale pojawiło się nowe wymaganie i musisz dodać nowe wymaganie do swojego kodu. To nowe wymaganie może spowodować uszkodzenie kodu w przypadku niektórych danych wejściowych (przypadku testowego).

Łatwym sposobem dostosowania tej zmiany jest użycie testów jednostkowych (JUNIT).
W tym celu podczas tworzenia bazy kodu należy napisać wiele przypadków testowych dla swojego kodu. A za każdym razem, gdy pojawia się nowe wymaganie, po prostu uruchamiasz wszystkie przypadki testowe, aby sprawdzić, czy któryś z nich się nie powiedzie. Jeśli nie, jesteś artystą BadA ** i możesz wdrożyć nowy kod.
Jeśli którykolwiek z przypadków testowych nie powiedzie się, zmieniasz kod i ponownie uruchamiasz przypadki testowe, aż uzyskasz zielony status.

Rohit Singh
źródło