Wiem, że jednym ze sposobów jest:
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
Czy jest na to lepszy sposób? (Prawdopodobnie używasz Junita @Rule
?)
java
unit-testing
junit
exception-handling
junit4
Ankit Dhingra
źródło
źródło
Odpowiedzi:
Podchodzisz do tego niewłaściwie. Po prostu przetestuj swoją funkcjonalność: jeśli zostanie zgłoszony wyjątek, test automatycznie się nie powiedzie. Jeśli nie zostanie zgłoszony żaden wyjątek, wszystkie testy zmienią kolor na zielony.
Od czasu do czasu zauważyłem, że to pytanie wzbudza zainteresowanie, więc trochę poszerzę.
Tło do testów jednostkowych
Podczas testowania jednostkowego ważne jest, aby określić, co uważasz za jednostkę pracy. Zasadniczo: ekstrakcja bazy kodu, która może, ale nie musi zawierać wiele metod lub klas reprezentujących jeden element funkcjonalności.
Lub, zgodnie z definicją w The Art of Unit Testing, 2nd Edition Roy Osherove , strona 11:
Ważne jest, aby zdawać sobie sprawę, że jedna jednostka pracy zwykle nie jest tylko jedną metodą, ale na bardzo podstawowym poziomie jest jedną metodą, a następnie jest kapsułkowana przez inną jednostkę pracy.
Najlepiej jest mieć metodę testową dla każdej oddzielnej jednostki pracy, aby zawsze można było natychmiast zobaczyć, co się dzieje. W tym przykładzie istnieje podstawowa metoda o nazwie
getUserById()
która zwróci użytkownika, i są w sumie 3 jednostki pracy.Pierwsza jednostka pracy powinna sprawdzić, czy prawidłowy użytkownik jest zwracany w przypadku prawidłowego i nieprawidłowego wprowadzenia.
Należy tutaj uwzględnić wszelkie wyjątki zgłaszane przez źródło danych: jeśli nie ma żadnego użytkownika, powinien zostać przeprowadzony test wykazujący, że wyjątek jest zgłaszany, gdy nie można go znaleźć. Przykładem może być ten,
IllegalArgumentException
który został złapany z@Test(expected = IllegalArgumentException.class)
adnotacją.Po obsłużeniu wszystkich przypadków użycia dla tej podstawowej jednostki pracy, przechodzisz na wyższy poziom. Tutaj robisz dokładnie to samo, ale radzisz sobie tylko z wyjątkami pochodzącymi z poziomu tuż poniżej bieżącego. Dzięki temu kod testowy jest dobrze ustrukturyzowany i pozwala szybko przeszukać architekturę, aby sprawdzić, gdzie coś pójdzie nie tak, zamiast przeskakiwać wszędzie.
Obsługa prawidłowych i błędnych danych wejściowych testu
W tym momencie powinno być jasne, jak poradzimy sobie z tymi wyjątkami. Istnieją 2 rodzaje danych wejściowych: prawidłowe dane wejściowe i błędne dane wejściowe (dane wejściowe są prawidłowe w ścisłym tego słowa znaczeniu, ale nie są prawidłowe).
Kiedy pracujesz z prawidłowymi danymi wejściowymi, ustawiasz niejawne oczekiwanie, że dowolny test, który napiszesz, zadziała.
Taka metoda połączenie może wyglądać następująco:
existingUserById_ShouldReturn_UserObject
. Jeśli ta metoda zawiedzie (np. Zgłoszony zostanie wyjątek), wiesz, że coś poszło nie tak i możesz zacząć kopać.Dodając kolejny test (
nonExistingUserById_ShouldThrow_IllegalArgumentException
), który wykorzystuje błędne dane wejściowe i oczekuje wyjątku, możesz sprawdzić, czy twoja metoda robi to, co powinna zrobić z nieprawidłowymi danymi wejściowymi.TL; DR
Próbowałeś zrobić dwie rzeczy w teście: sprawdź, czy dane wejściowe są prawidłowe i błędne. Dzieląc to na dwie metody, z których każda robi jedną rzecz, uzyskasz o wiele jaśniejsze testy i znacznie lepszy przegląd tego, co się nie powiedzie.
Pamiętając o warstwowej jednostce prac, możesz również zmniejszyć liczbę testów potrzebnych dla warstwy znajdującej się wyżej w hierarchii, ponieważ nie musisz uwzględniać wszystkich rzeczy, które mogły pójść nie tak w niższych warstwach: warstwy poniżej bieżącej są wirtualną gwarancją, że twoje zależności działają, a jeśli coś pójdzie nie tak, znajduje się w twojej bieżącej warstwie (zakładając, że niższe warstwy nie powodują żadnych błędów).
źródło
expected
adnotacji. Jeśli chcesz przetestować scenariusz, w którym kod zawiedzie i chcesz sprawdzić, czy błąd został poprawnie obsłużony: użyjexpected
i być może użyj aserts, aby ustalić, czy problem został rozwiązany.throws IllegalArgumentException
do testu. Na końcu chcesz, aby Twój test zmienił kolor na czerwony, jeśli istnieje wyjątek. Zastanów się? Nie musisz pisaćfail()
. Jak napisał @Jeroen Vannevel: „jeśli zostanieNatknąłem się na to z powodu zasady SonarQube „squid: S2699”: „Dodaj co najmniej jedno stwierdzenie do tego przypadku testowego”.
Miałem prosty test, którego jedynym celem było przejście bez rzucania wyjątków.
Rozważ ten prosty kod:
Jakiego rodzaju twierdzenie można dodać, aby przetestować tę metodę? Jasne, możesz spróbować go złapać, ale to tylko rozdęcie kodu.
Rozwiązanie pochodzi od samego JUnit.
Jeśli nie zostanie zgłoszony żaden wyjątek i chcesz jawnie zilustrować to zachowanie, po prostu dodaj,
expected
jak w poniższym przykładzie:Test.None.class
jest domyślną wartością oczekiwaną.źródło
Dzięki płynnym stwierdzeniom AssertJ 3.7.0 :
źródło
JUnit 5 (Jupiter) zapewnia trzy funkcje sprawdzania nieobecności / obecności wyjątku:
●
assertAll()
Zapewnia, że wszystkie dostarczone
executables
nie wyrzucają wyjątków.
●
assertDoesNotThrow()
Zapewnia, że wykonanie
dostarczonego
executable
/supplier
nie rzuca żadnego wyjątku .
Ta funkcja jest dostępna
od wersji JUnit 5.2.0 (29 kwietnia 2018 r.).
●
assertThrows()
Zapewnia, że wykonanie dostarczonego
executable
generuje wyjątek
expectedType
i zwraca wyjątek .
Przykład
źródło
Java 8 sprawia, że jest to o wiele łatwiejsze, a Kotlin / Scala podwójnie.
Możemy napisać małą klasę użytkową
a wtedy twój kod staje się po prostu:
Jeśli nie masz dostępu do Java-8, użyłbym boleśnie starej funkcji Java: bloki kodu aribitrary i prosty komentarz
I wreszcie, z kotlin, językiem, w którym ostatnio się zakochałem:
Chociaż jest dużo miejsca na majstrowanie przy tym, jak chcesz to wyrazić, zawsze byłem fanem płynnych zapewnień .
Jeżeli chodzi o
Zasadniczo jest to poprawne, ale wniosek jest błędny.
Java dopuszcza wyjątki dla przepływu kontroli. Odbywa się to przez samo środowisko wykonawcze JRE w interfejsach API, takich jak
Double.parseDouble
aNumberFormatException
iPaths.get
aInvalidPathException
.Biorąc pod uwagę, że napisałeś komponent, który sprawdza ciągi liczbowe
Double.ParseDouble
, być może przy użyciu Regex, może ręcznie analizatora składni lub może coś, co zawiera inne reguły domeny, które ograniczają zakres liczby podwójnej do czegoś konkretnego, jak najlepiej to przetestować składnik? Myślę, że oczywistym testem byłoby stwierdzenie, że podczas analizowania łańcucha wynikowego nie jest zgłaszany żaden wyjątek. Chciałbym napisać ten test przy użyciu powyższegoassertDoesNotThrow
lub/*comment*/{code}
bloku. Coś jakZachęcam również do sparametryzowania tego testu przy
input
użyciuTheories
lub wParameterized
celu łatwiejszego ponownego użycia tego testu dla innych danych wejściowych. Alternatywnie, jeśli chcesz iść egzotycznie, możesz wybrać narzędzie do generowania testów (i to ). TestNG ma lepszą obsługę testów sparametryzowanych.Szczególnie nieprzyjemne jest dla mnie zalecenie użycia
@Test(expectedException=IllegalArgumentException.class)
, ten wyjątek jest niebezpiecznie szeroki . Jeśli Twój kod zmieni się tak, że ma to w konstruktorze testowanego komponentuif(constructorArgument <= 0) throw IllegalArgumentException()
, a Twój test podaje 0 dla tego argumentu, ponieważ jest to wygodne - i jest to bardzo powszechne, ponieważ dobre generowanie danych testowych jest zaskakująco trudnym problemem - wtedy twój test pojawi się zielony pasek, mimo że nic nie testuje. Taki test jest gorszy niż bezużyteczny.źródło
Assert.assertThrows
aby sprawdzić, czy jakiś kod zgłasza wyjątek.Jeśli masz pecha, aby złapać wszystkie błędy w kodzie. Możesz głupio zrobić
źródło
Exception ex
powinna być= null;
zanim będziesz mógł ją przetestować.JUnit5 dodaje metodę assertAll () właśnie w tym celu.
źródło: JUnit 5 API
źródło
Chociaż ten post ma już 6 lat, wiele się zmieniło w świecie Junit. Dzięki Junit5 możesz teraz używać
Dawny:
Mam nadzieję, że pomoże to osobom korzystającym z nowszej wersji Junit5
źródło
Awaitility
„suntilAsserted(ThrowingRunnable assertion)
. Testowany system obecnie rzuca określony wyjątek na udostępnianą przeze mnie funkcję ThrowingRunnable, ale chcę dać temu trochę czasu, aż przestanie to robić. Jeśli jednak rzuciłby to inny wyjątek, chciałbym, aby test natychmiast się nie powiódł.Jeśli chcesz sprawdzić, czy cel testowy korzysta z wyjątku. Po prostu zostaw test jako (próbny współpracownik używający jMock2):
Test zostanie zaliczony, jeśli Twój cel wykorzysta zgłoszony wyjątek, w przeciwnym razie test się nie powiedzie.
Jeśli chcesz przetestować logikę zużycia wyjątków, sprawy stają się bardziej złożone. Sugeruję przekazanie konsumpcji współpracownikowi, który mógłby zostać wyszydzony. Dlatego test może być:
Ale czasami jest przeprojektowany, jeśli chcesz go tylko zalogować. W takim przypadku ten artykuł ( http://java.dzone.com/articles/monitoring-declarative-transac , http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there -an-easy-way / ) może pomóc, jeśli nalegasz na tdd w tym przypadku.
źródło
Użyj assertNull (...)
źródło
assertNull
nigdy nie jest wykonywany. Jednak szybki czytelnik ma wrażenie, że poczyniono stwierdzenie, które naprawdę weryfikuje przypadek nieprzerzucania. Innymi słowy: jeśli zostanie osiągnięty blok catch, wyjątek jest zawsze różny od zera - można go zatem zastąpić prostymfail
.assertNull(e)
zgłosi test jako nieudany, jak stwierdzono,e
nie może byćnull
wcatch
bloku ... Mike, to jest po prostu dziwne programowanie: - /. .. tak przynajmniej użyj,fail()
jak mówi AndreasMożna oczekiwać, że wyjątek nie zostanie zgłoszony przez utworzenie reguły.
źródło
To może nie być najlepszy sposób, ale zdecydowanie upewnia się, że wyjątek nie zostanie zgłoszony z testowanego bloku kodu.
źródło
Możesz to zrobić za pomocą @Rule, a następnie wywołać metodę reportMissingExceptionWithMessage, jak pokazano poniżej: To jest kod Scala.
źródło
private val
? Co to za język? Najwyraźniej nie Java; p Proszę nie podawać kodu jako zrzutu ekranu, nie jest mile widziany.Następujący test kończy się niepowodzeniem dla wszystkich wyjątków, zaznaczonych lub niezaznaczonych:
źródło
Możesz tworzyć dowolne własne asercje na podstawie asercji z junit:
I przetestuj:
Ogólnie rzecz biorąc, istnieje możliwość natychmiastowego niepowodzenia testu („bla bla bla”) w dowolnym scenariuszu, w dowolnym miejscu, w którym ma to sens. Na przykład użyj go w bloku try / catch, aby zawieść, jeśli coś zostanie rzucone w przypadku testowym:
Oto próbka metody, którą testujemy, zakładając, że mamy taką metodę, która nie może zawieść w określonych okolicznościach, ale może się nie powieść:
Powyższa metoda jest prostą próbką. Ale działa to w skomplikowanych sytuacjach, w których awaria nie jest tak oczywista. Istnieją import:
źródło