werfen geprüft Ausnahmen von Verspottungen mit Mockito

173

Ich versuche, eines meiner verspotteten Objekte eine markierte Ausnahme auslösen zu lassen, wenn eine bestimmte Methode aufgerufen wird. Ich versuche Folgendes.

@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 {
}

Dies führt jedoch zu folgendem Fehler.

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

Wenn man sich die Mockito-Dokumentation ansieht , die sie nur verwenden RuntimeException, ist es nicht möglich, mit Mockito geprüfte Ausnahmen von einem Scheinobjekt zu werfen?

Arthur Maltson
quelle

Antworten:

221

Überprüfen Sie die Java-API auf Liste .
Die get(int index)Methode wird deklariert, um nur das zu werfen, IndexOutOfBoundExceptionwas sich erstreckt RuntimeException.
Sie versuchen, Mockito anzuweisen, eine Ausnahme auszulösen, SomeException()die nicht gültig ist, um von diesem bestimmten Methodenaufruf ausgelöst zu werden .

Zur weiteren Klärung.
Die List- Schnittstelle sieht nicht vor, dass eine aktivierte Ausnahme von der get(int index)Methode ausgelöst wird. Aus diesem Grund schlägt Mockito fehl.
Wenn Sie die verspottete Liste erstellen , verwendet Mockito die Definition von List .class, um die verspottete Liste zu erstellen .

Das Verhalten, das Sie mit angeben, when(list.get(0)).thenThrow(new SomeException()) stimmt nicht mit der Methodensignatur in der Listen-API überein , da die get(int index)Methode nicht ausgelöst wirdSomeException() und Mockito fehlschlägt.

Wenn Sie dies wirklich tun möchten, lassen Sie Mockito einen new RuntimeException()oder noch besser einen werfen, new ArrayIndexOutOfBoundsException()da die API angibt, dass dies die einzige gültige Ausnahme ist, die ausgelöst wird.

John Engelman
quelle
Während mein echter Code List nicht wirklich verwendete, gilt Ihre Antwort auch für diesen Methodenaufruf. Ich habe mich über die falsche Methode lustig gemacht. Danke dir.
Arthur Maltson
2
extra: Mocktio wird sich nicht beschweren, wenn Sie eine Methode ohne Throwables werfen, aber Sie werden auch diese Ausnahme bekommen
Dwana
8
Für Kotliner: Kotlin hat keine Ausnahmen überprüft, daher können Sie normalerweise (in der Funktionssignatur) nicht deklarieren, dass die Funktion eine Ausnahme auslöst. Sie können die Funktion jedoch mit ThrowsAnmerkungen versehen, damit der Compiler denselben Bytecode generiert wie beim Deklarieren von Würfen im entsprechenden Java-Code. Weitere Informationen finden Sie unter [hier] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/… ).
Javad Sadeqzadeh
1
Diese Prüfung wird seit der Veröffentlichung von Mockito 2.11.0 erzwungen (siehe 2.10.3) .
JJD
105

Eine Problemumgehung besteht darin, eine willAnswer()Methode zu verwenden.

Zum Beispiel funktioniert das Folgende (und MockitoExceptionwirft kein, sondern wirft tatsächlich ein Häkchen, Exceptionwie hier erforderlich) mit BDDMockito:

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

Das Äquivalent für Mockito würde die doAnswerMethode verwenden

Deepak
quelle
9
oder verwenden, willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);wenn die Methode zurückkehrt void.
Julien Kronegg
9
oder verwenden Sie when (someObj.someMethod (stringArg1)). thenAnswer (Aufruf -> {neue Ausnahme auslösen ("abc msg");});
Dmitri Algazin
Tolle Problemumgehung, danke! Für Kotliner, die (1) dies nahtlos als Erweiterungsfunktion verwenden und (2) mehrere Argumente übergeben möchten, wie es willThrow()normalerweise zulässig ist, habe ich einen Gist geschrieben
David Ferrand
2
oder doAnswervonnhaarman.mockitokotlin2
hmac
6

Beachten Sie, dass in der Regel Mockito nicht geprüfte Ausnahmen werfen lassen , so lange die Ausnahme in der Nachrichtensignatur deklariert wird. Zum Beispiel gegeben

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

interface Foo {
  Bar frob() throws BarException
}

Es ist legal zu schreiben:

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

Wenn Sie jedoch eine aktivierte Ausnahme auslösen, die nicht in der Methodensignatur deklariert ist, z

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

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

Mockito schlägt zur Laufzeit mit der etwas irreführenden, generischen Meldung fehl:

Checked exception is invalid for this method!
Invalid: QuxException

Dies kann dazu führen, dass Sie glauben, dass geprüfte Ausnahmen im Allgemeinen nicht unterstützt werden. Tatsächlich versucht Mockito jedoch nur, Ihnen mitzuteilen, dass diese geprüfte Ausnahme für diese Methode nicht gültig ist .

David Moles
quelle
5

Mit Kotlin gibt es die Lösung:

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

Woher kommt kommt

import org.mockito.BDDMockito.given

Kevin ABRIOUX
quelle
1

Das funktioniert bei mir in Kotlin:

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

Hinweis: Wirf eine andere definierte Ausnahme als Exception () aus.

Alok Gupta
quelle
Genau das, wonach ich gesucht habe, kann jede andere Ausnahme Exception
auslösen