melempar Pengecualian yang dicentang dari mengejek dengan Mockito

173

Saya mencoba untuk membuat salah satu benda tiruan saya melemparkan Pengecualian yang diperiksa ketika metode tertentu dipanggil. Saya mencoba yang berikut ini.

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

Namun, itu menghasilkan kesalahan berikut.

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

Melihat dokumentasi Mockito , mereka hanya menggunakan RuntimeException, apakah tidak mungkin untuk membuang Pengecualian yang diperiksa dari objek tiruan dengan Mockito?

Arthur Maltson
sumber

Jawaban:

221

Periksa Java API untuk Daftar .
The get(int index)dideklarasikan untuk melemparkan hanya IndexOutOfBoundExceptionyang meluas RuntimeException.
Anda mencoba memberi tahu Mockito untuk melemparkan pengecualian SomeException()yang tidak valid untuk dilemparkan oleh pemanggilan metode tertentu .

Untuk memperjelas lebih lanjut.
The Daftar antarmuka tidak menyediakan untuk Exception diperiksa untuk dilempar dari get(int index)metode dan itulah sebabnya Mockito gagal.
Saat Anda membuat Daftar yang diolok - olok , Mockito akan menggunakan definisi Daftar .class untuk membuat tiruannya.

Perilaku yang Anda tentukan dengan when(list.get(0)).thenThrow(new SomeException()) tidak cocok dengan tanda tangan metode di API Daftar , karena get(int index)metode tidak melemparSomeException() sehingga Mockito gagal.

Jika Anda benar-benar ingin melakukan ini, mintalah Mockito melempar new RuntimeException()atau lebih baik melempar new ArrayIndexOutOfBoundsException()karena API menetapkan bahwa itu adalah satu-satunya Pengecualian yang valid untuk dilemparkan.

John Engelman
sumber
Walaupun kode saya yang sebenarnya tidak benar-benar menggunakan Daftar, jawaban Anda juga berlaku untuk pemanggilan metode itu. Saya mengejek metode yang salah. Terima kasih.
Arthur Maltson
2
tambahan: Mocktio tidak akan mengeluh jika kamu melakukannya. Melemparkan metode tanpa lemparan, tetapi kamu juga akan mendapatkan pengecualian ini
dwana
8
Untuk Kotliners: Kotlin tidak memiliki pengecekan pengecualian, jadi Anda biasanya tidak dapat menyatakan (dalam tanda tangan fungsi) bahwa fungsi tersebut melempar pengecualian. Namun, Anda dapat membuat anotasi fungsi dengan Throwsanotasi untuk membuat kompiler menghasilkan bytecode yang sama dengan mendeklarasikan lemparan dalam kode Java yang setara. Lihat [di sini] ( kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-throws/… ) untuk detail lebih lanjut.
Javad Sadeqzadeh
1
Pemeriksaan ini diberlakukan sejak rilis Mockito 2.11.0 (lihat 2.10.3) .
JJD
106

Solusinya adalah menggunakan willAnswer()metode.

Misalnya karya-karya berikut (dan tidak melempar MockitoExceptiontetapi sebenarnya melempar yang diperiksa Exceptionseperti yang disyaratkan di sini) menggunakan BDDMockito:

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

Setara dengan Mockito biasa akan menggunakan doAnswermetode ini

Deepak
sumber
9
atau gunakan willAnswer( invocation -> { throw new Exception("abc msg"); }).given(someObj).someMethod(stringArg1);saat metode kembali void.
Julien Kronegg
9
atau gunakan ketika (someObj.someMethod (stringArg1)). thenAnswer (doa -> {throw new Exception ("abc msg");});
Dmitri Algazin
Solusi hebat, terima kasih! Untuk Kotliners yang ingin (1) menggunakannya secara mulus sebagai fungsi ekstensi dan (2) dapat melewati beberapa argumen seperti willThrow()biasanya memungkinkan, saya telah menulis Intisari
David Ferrand
2
atau doAnswerdarinhaarman.mockitokotlin2
hmac
6

Perhatikan bahwa secara umum, Mockito tidak memungkinkan melemparkan pengecualian diperiksa selama pengecualian dinyatakan dalam tanda tangan pesan. Misalnya, diberikan

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

interface Foo {
  Bar frob() throws BarException
}

itu legal untuk menulis:

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

Namun, jika Anda melempar pengecualian yang dicentang tidak dinyatakan dalam metode tanda tangan, mis

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

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

Mockito akan gagal saat runtime dengan pesan umum yang agak menyesatkan:

Checked exception is invalid for this method!
Invalid: QuxException

Hal ini dapat menyebabkan Anda untuk percaya bahwa pengecualian diperiksa pada umumnya tidak didukung, tetapi sebenarnya Mockito hanya mencoba untuk memberitahu Anda bahwa ini pengecualian diperiksa tidak berlaku untuk metode ini .

David Moles
sumber
5

Ada solusi dengan Kotlin:

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

Dari mana datangnya

impor org.mockito.BDDMockito.given

Kevin ABRIOUX
sumber
1

Ini bekerja untuk saya di Kotlin:

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

Catatan: Lempar pengecualian apa pun yang ditentukan selain Pengecualian ()

Alok Gupta
sumber
Hanya apa yang saya cari, dapat membuang Pengecualian apa pun selainException
Naeem Sarfraz