Simulasikan panggilan pertama gagal, panggilan kedua berhasil

119

Saya ingin menggunakan Mockito untuk menguji kode (yang disederhanakan) di bawah ini. Saya tidak tahu bagaimana memberi tahu Mockito untuk gagal pertama kali, lalu berhasil untuk kedua kalinya.

for(int i = 1; i < 3; i++) {
  String ret = myMock.doTheCall();

  if("Success".equals(ret)) {
    log.write("success");
  } else if ( i < 3 ) {
    log.write("failed, but I'll try again. attempt: " + i);
  } else {
    throw new FailedThreeTimesException();
  }
}

Saya dapat menyiapkan tes sukses dengan:

Mockito.when(myMock).doTheCall().thenReturn("Success");

Dan uji kegagalan dengan:

Mockito.when(myMock).doTheCall().thenReturn("you failed");

Tapi bagaimana saya bisa menguji bahwa jika gagal sekali (atau dua kali) lalu berhasil, tidak masalah?

jb.
sumber

Jawaban:

250

Dari dokumen :

Kadang-kadang kita perlu stub dengan nilai pengembalian / pengecualian yang berbeda untuk pemanggilan metode yang sama. Kasus penggunaan tipikal bisa jadi memperolok iterator. Versi asli Mockito tidak memiliki fitur ini untuk mempromosikan ejekan sederhana. Misalnya, alih-alih iterator, seseorang dapat menggunakan Iterable atau hanya koleksi. Mereka menawarkan cara-cara stubbing yang alami (misalnya menggunakan koleksi asli). Dalam skenario yang jarang terjadi, menghentikan panggilan berturut-turut dapat berguna, meskipun:

when(mock.someMethod("some arg"))
   .thenThrow(new RuntimeException())
  .thenReturn("foo");

//First call: throws runtime exception:
mock.someMethod("some arg");

//Second call: prints "foo"
System.out.println(mock.someMethod("some arg"));

Jadi dalam kasus Anda, Anda ingin:

when(myMock.doTheCall())
   .thenReturn("You failed")
   .thenReturn("Success");
Jon Skeet
sumber
25
Ini mengarahkan saya ke arah yang benar (terima kasih) untuk skenario saya yang berhubungan dengan metode void - dalam hal ini Anda perlu menggunakan gaya alternatif ...doThrow(new RuntimeException()).doNothing().when(myMock).doTheCall();
haggisandchips
38

Cara terpendek untuk menulis apa yang Anda inginkan adalah

when(myMock.doTheCall()).thenReturn("Success", "you failed");

Saat Anda memberikan beberapa argumen untuk thenReturnseperti ini, setiap argumen akan digunakan paling banyak sekali, kecuali untuk argumen terakhir, yang digunakan sebanyak yang diperlukan. Misalnya, dalam kasus ini, jika Anda melakukan panggilan 4 kali, Anda akan mendapatkan "Sukses", "Anda gagal", "Anda gagal", "Anda gagal".

Dawood ibn Kareem
sumber
22

Karena komentar yang berkaitan dengan ini sulit dibaca, saya akan menambahkan jawaban yang diformat.

Jika Anda mencoba melakukan ini dengan voidfungsi yang hanya mengeluarkan pengecualian, diikuti dengan langkah tanpa perilaku, Anda akan melakukan sesuatu seperti ini:

Mockito.doThrow(new Exception("MESSAGE"))
            .doNothing()
            .when(mockService).method(eq());
anoneironaut
sumber
4

Untuk menambahkan ini dan jawaban ini , Anda juga dapat menggunakan loop untuk merangkai panggilan palsu. Ini berguna jika Anda perlu mengejek hal yang sama beberapa kali, atau mengejek dalam beberapa pola.

Misalnya (meskipun terlalu dibuat-buat):

import org.mockito.stubbing.Stubber;

Stubber stubber = doThrow(new Exception("Exception!"));
for (int i=0; i<10; i++) {
    if (i%2 == 0) {
        stubber.doNothing();
    } else {
        stubber.doThrow(new Exception("Exception"));
    }
}
stubber.when(myMockObject).someMethod(anyString());
typoerrpr
sumber
Saya sebenarnya tidak tahu tentang Stubber ini dan merasa berguna, +1.
Mihai Morcov
Ini harus menjadi jawaban yang tepat jika Anda membutuhkan panggilan metode void.
db80
4

Saya memiliki situasi yang berbeda, saya ingin mengejek suatu voidfungsi untuk panggilan pertama dan menjalankannya secara normal pada panggilan kedua.

Ini bekerja untuk saya:

Mockito.doThrow(new RuntimeException("random runtime exception"))
       .doCallRealMethod()
       .when(spy).someMethod(Mockito.any());
Mohammed Elrashidy
sumber