rzut zaznaczony Wyjątki od mocków z Mockito

173

Próbuję, aby jeden z mockowanych obiektów rzucał sprawdzony wyjątek, gdy wywoływana jest określona metoda. Próbuję następujących rzeczy.

@Test(expectedExceptions = SomeException.class)
public void throwCheckedException() {
    List<String> list = mock(List.class);
    when(list.get(0)).thenThrow(new SomeException());
    String test = list.get(0);
}

public class SomeException extends Exception {
}

Jednak powoduje to następujący błąd.

org.testng.TestException: 
Expected exception com.testing.MockitoCheckedExceptions$SomeException but got org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: com.testing.MockitoCheckedExceptions$SomeException

Patrząc na dokumentację Mockito , używają tylko RuntimeException, czy nie można wrzucić sprawdzonych wyjątków z pozorowanego obiektu za pomocą Mockito?

Arthur Maltson
źródło

Odpowiedzi:

221

Sprawdź API Java dla listy . Metoda jest zadeklarowana rzucić tylko która rozciąga . Próbujesz powiedzieć Mockito, aby zgłosił wyjątek, który nie może zostać wyrzucony przez to konkretne wywołanie metody .
get(int index)IndexOutOfBoundExceptionRuntimeException
SomeException()

Aby wyjaśnić dalej. Lista interfejs nie przewiduje sprawdzonej wyjątek zostać wyrzucony z metodą i dlatego Mockito zawodzi. Podczas tworzenia fałszywej listy , Mockito użyje definicji listy .class do stworzenia jej makiety.
get(int index)

Zachowanie określane za pomocą polecenia when(list.get(0)).thenThrow(new SomeException()) nie jest zgodne z sygnaturą metody w interfejsie List API , ponieważ get(int index)metoda nieSomeException() zgłasza, więc Mockito zawodzi.

Jeśli naprawdę chcesz to zrobić, niech Mockito rzuci a, new RuntimeException()a nawet lepiej, new ArrayIndexOutOfBoundsException()ponieważ API określa, że ​​jest to jedyny prawidłowy wyjątek do wyrzucenia.

John Engelman
źródło
Chociaż mój prawdziwy kod w rzeczywistości nie używa listy, Twoja odpowiedź dotyczy również tego wywołania metody. Kpiłem z niewłaściwej metody. Dziękuję Ci.
Arthur Maltson,
2
extra: Mocktio nie będzie narzekać, jeśli to zrobisz Rzuć metodę bez żadnych przedmiotów miotających, ale dostaniesz również ten wyjątek
dwana
8
Dla Kotliners: Kotlin nie ma sprawdzonych wyjątków, więc nie można normalnie zadeklarować (w sygnaturze funkcji), że funkcja zgłasza wyjątek. Można jednak dodać do funkcji Throwsadnotację, aby kompilator wygenerował ten sam kod bajtowy, co deklarowanie rzutów w równoważnym kodzie Java. Więcej informacji można znaleźć [tutaj] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/… ).
Javad Sadeqzadeh
1
To sprawdzenie jest wymuszane od wydania Mockito 2.11.0 (patrz 2.10.3) .
JJD
106

Rozwiązaniem jest użycie willAnswer()metody.

Na przykład poniższe działa (i nie MockitoExceptionzgłasza a, ale w rzeczywistości rzuca zaznaczenie Exceptionzgodnie z wymaganiami) przy użyciu BDDMockito:

given(someObj.someMethod(stringArg1)).willAnswer( invocation -> { throw new Exception("abc msg"); });

Odpowiednik dla zwykłego Mockito użyłby tej doAnswermetody

Deepak
źródło
9
lub użyj, willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);gdy metoda zwraca void.
Julien Kronegg
9
lub użyj when (someObj.someMethod (stringArg1)). thenAnswer (wywołanie -> {throw new Exception ("abc msg");});
Dmitri Algazin
Świetne obejście, dzięki! Dla Kotlinerów, którzy chcą (1) używać tego bezproblemowo jako funkcji rozszerzającej i (2) być w stanie przekazać kilka argumentów, jak willThrow()zwykle pozwala, napisałem Gist
David Ferrand
2
lub doAnswerodnhaarman.mockitokotlin2
hmac
6

Należy zauważyć, że w ogóle, Mockito ma umożliwić wyrzucanie sprawdzonych wyjątków, tak długo, jak wyjątek jest zadeklarowana w podpisie wiadomości. Na przykład podane

class BarException extends Exception {
  // this is a checked exception
}

interface Foo {
  Bar frob() throws BarException
}

legalne jest pisanie:

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(BarException.class)

Jeśli jednak wyrzucisz sprawdzony wyjątek niezadeklarowany w sygnaturze metody, np

class QuxException extends Exception {
  // a different checked exception
}

Foo foo = mock(Foo.class);
when(foo.frob()).thenThrow(QuxException.class)

Mockito zawiedzie w czasie wykonywania z nieco mylącym, ogólnym komunikatem:

Checked exception is invalid for this method!
Invalid: QuxException

Może to prowadzić do przekonania, że ​​zaznaczone wyjątki generalnie nie są obsługiwane, ale w rzeczywistości Mockito próbuje tylko powiedzieć, że ten sprawdzony wyjątek nie jest ważny dla tej metody .

David Moles
źródło
5

Jest rozwiązanie z Kotlinem:

given(myObject.myCall()).willAnswer {
    throw IOException("Ooops")
}

Skąd pochodzi

import org.mockito.BDDMockito.given

Kevin ABRIOUX
źródło
1

To działa dla mnie w Kotlinie:

when(list.get(0)).thenThrow(new ArrayIndexOutOfBoundsException());

Uwaga: zgłoś dowolny zdefiniowany wyjątek inny niż Exception ()

Alok Gupta
źródło
Właśnie to, czego szukałem, może rzucić każdy wyjątek inny niżException
Naeem Sarfraz