lancia eccezioni verificate da derisioni con Mockito


173

Sto cercando di far lanciare un'eccezione controllata a uno dei miei oggetti derisi quando viene chiamato un metodo particolare. Sto provando quanto segue.

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

Tuttavia, ciò produce il seguente errore.

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

Guardando la documentazione di Mockito , usano solo RuntimeException, non è possibile lanciare eccezioni verificate da un oggetto simulato con Mockito?

Risposte:


221

Controlla l'API Java per l' elenco .
Il get(int index)metodo è dichiarato per lanciare solo ciò IndexOutOfBoundExceptionche si estende RuntimeException.
Stai cercando di dire a Mockito di lanciare un'eccezione SomeException()che non è valida per essere lanciata da quel particolare metodo .

Per chiarire ulteriormente.
L' interfaccia Elenco non prevede get(int index)che venga generata un'eccezione selezionata dal metodo ed è per questo che Mockito non riesce.
Quando crei l' Elenco deriso , Mockito utilizzerà la definizione di .class Elenco per crearne il mock.

Il comportamento che stai specificando con when(list.get(0)).thenThrow(new SomeException()) non corrisponde alla firma del metodo nell'API List , perché il get(int index)metodo non generaSomeException() quindi Mockito non riesce.

Se vuoi davvero farlo, fai in modo che Mockito lanci una new RuntimeException()o anche meglio una new ArrayIndexOutOfBoundsException()poiché l'API specifica che questa è l'unica Eccezione valida da lanciare.


Mentre il mio vero codice non stava effettivamente usando Elenco, la tua risposta si applica anche a quella chiamata del metodo. Stavo deridendo il metodo sbagliato. Grazie.
Arthur Maltson,

2
extra: Mocktio non si lamenterà se lo fai Getta un metodo senza gettabili, ma otterrai anche questa eccezione
dwana,

8
Per Kotliners: Kotlin non ha verificato le eccezioni, quindi normalmente non è possibile dichiarare (nella firma della funzione) che la funzione genera un'eccezione. Tuttavia, è possibile annotare la funzione con Throwsannotazione per fare in modo che il compilatore generi lo stesso bytecode che dichiara i lanci nel codice Java equivalente. Vedi [qui] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/… ) per maggiori dettagli.
Javad Sadeqzadeh,

1
Questo controllo è applicato dal rilascio di Mockito 2.11.0 (vedi 2.10.3) .
JJD

106

Una soluzione alternativa consiste nell'utilizzare un willAnswer()metodo.

Ad esempio, i seguenti lavori (e non generano un MockitoExceptionma in realtà generano un segno di spunta Exceptioncome richiesto qui) usando BDDMockito:

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

L'equivalente per il semplice Mockito dovrebbe usare il doAnswermetodo


9
o utilizzare willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);quando il metodo ritorna void.
Julien Kronegg,

9
oppure usa when (someObj.someMethod (stringArg1)). thenAnswer (invocation -> {lancia nuova eccezione ("abc msg");});
Dmitri Algazin,

Ottima soluzione, grazie! Per i Kotliner che vogliono (1) usarlo senza problemi come funzione di estensione e (2) essere in grado di passare diversi argomenti come willThrow()normalmente consente, ho scritto un Gist
David Ferrand

2
o doAnswerdanhaarman.mockitokotlin2
hmac il

6

Si noti che, in generale, Mockito non permette gettare eccezioni controllate fintanto che l'eccezione è dichiarato nella firma del messaggio. Ad esempio, dato

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

interface Foo {
  Bar frob() throws BarException
}

è legale scrivere:

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

Tuttavia, se si genera un'eccezione controllata non dichiarata nella firma del metodo, ad es

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

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

Mockito fallirà in fase di esecuzione con il messaggio generico un po 'fuorviante:

Checked exception is invalid for this method!
Invalid: QuxException

Questo può farti credere che le eccezioni verificate in generale non siano supportate, ma in realtà Mockito sta solo cercando di dirti che questa eccezione verificata non è valida per questo metodo .


5

C'è la soluzione con Kotlin:

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

Da dove viene

import org.mockito.BDDMockito.given


1

Questo funziona per me in Kotlin:

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

Nota: genera qualsiasi eccezione definita diversa da Exception ()


Proprio quello che stavo cercando, può generare qualsiasi eccezione diversa daException
Naeem Sarfraz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.