Cara memverifikasi beberapa panggilan metode dengan parameter berbeda

116

Saya memiliki metode berikut yang ingin saya verifikasi perilakunya.

public void methodToTest(Exception e, ActionErrors errors) {
    ...

    errors.add("exception.message", 
            ActionMessageFactory.createErrorMessage(e.toString()));

    errors.add("exception.detail",
            ActionMessageFactory.createErrorMessage(e.getStackTrace()[0].toString()));

    ...
}

Di kelas @Test saya, saya berharap melakukan sesuatu seperti ini untuk memverifikasi yang errors.add()disebut dengan "exception.message" dan sekali lagi dengan "exception.detail"

verify(errors).add(eq("exception.message"), any(ActionError.class));
verify(errors).add(eq("exception.detail"), any(ActionError.class));

Namun Mockito mengeluh sebagai berikut

Argument(s) are different! Wanted:
actionErrors.add(
    "exception.message",
    <any>
);

Actual invocation has different arguments:
actionErrors.add(
    "exception.detail",
    org.apache.struts.action.ActionError@38063806
);

Bagaimana cara memberi tahu Mockito untuk memeriksa kedua nilai?

Brad
sumber
1
ketika Anda memiliki 2 metode dengan tanda tangan yang berbeda, Anda dapat menulis kasus uji terpisah untuk keduanya.
Naveen Babu
8
Ya, tetapi dalam kasus ini tanda tangan metode yang sama tetapi hanya nilai argumen yang berbeda
Brad
Anda dapat mencoba menggunakanMockito.reset()
takacsot

Jawaban:

102

Bacaan lebih lanjut telah membuat saya mencoba menggunakan ArgumentCaptors dan karya-karya berikut, meskipun jauh lebih bertele-tele daripada yang saya inginkan.

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);

verify(errors, atLeastOnce()).add(argument.capture(), any(ActionMessage.class));

List<String> values = argument.getAllValues();

assertTrue(values.contains("exception.message"));
assertTrue(values.contains("exception.detail"));
Brad
sumber
apakah ada cara untuk memastikan bahwa parameter tertentu dipasangkan menggunakan pendekatan ini? Katakanlah misalnya metode OP memiliki dua argumen dan ingin memverifikasi bahwa mereka dipanggil bersama
berkomitmen dan
1
Kasus uji OP memanggil methodToTest()tepat satu kali, oleh karena itu jawaban ini memverifikasi bahwa kedua panggilan dibuat bersamaan. Rekaman List<String> valuesyang sedang ditegaskan hanya akan berisi dua nilai yang sedang diuji dan tidak ada yang lain. Anda juga bisa menambahkan assertTrue(values.size == 2). Jika ini yang Anda inginkan, saya akan mengganti 3 pernyataan assertTrue dengan satu Hamcrest ...assertThat(values, contains("exception.message", "exception.detail"));
Brad
bukankah kasus uji OP memanggil methodToTest () dua kali?
committedandroider
maaf saya tidak jelas. Saya mengacu pada skenario di mana OP ingin menguji bahwa dua argumen dipanggil bersamaan. Jadi tanda tangan metode akan terlihat seperti public void methodToTest (Exception e, Message m, error ActionErrors) {sehingga pengecualian tertentu dipanggil dengan pesan tertentu. Saya menduga bahwa Anda hanya bisa memiliki dua ArgumentCaptors dan kemudian mengambil indeks dan membandingkan dengan menggunakan nilai-nilai di indeks tersebut di kedua daftar nilai
committedandroider
Kasus uji OP memanggil methodToTest()sekali. Ini adalah metode argumen ActionErrors errorsyang dipanggil secara internal dua kali.
Brad
61

Jika urutan kedua add()panggilan relevan, Anda dapat menggunakan InOrder:

InOrder inOrder = inOrder(errors);
inOrder.verify(errors).add(eq("exception.message"), any(ActionError.class));
inOrder.verify(errors).add(eq("exception.detail"), any(ActionError.class));
Christoph Walesch
sumber
7
Cukup untuk melewatkan satu errorsargumen: InOrder inOrder = inOrder(errors);(lihat dokumen )
GreenhouseVeg
2
Bagaimana jika pesanan TIDAK relevan? yang sering terjadi.
haelix
1
@haelix Jika demikian, gunakan jawaban Brads. Ubah Listmenjadi Setdan tegaskan bahwa Kumpulan masukan sama dengan himpunan yang diberikan oleh argumen menangkap.
flopshot
25

Coba sesuatu seperti ini:

verify(errors, times(2))
     .add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
          any(ActionError.class));
John B
sumber
5
Cek Anda jelas terlalu santai.
haelix
17

Anda mungkin memiliki masalah dalam kode Anda. Karena sebenarnya Anda menulis kode ini:

Map<Character, String> map = mock(Map.class);

map.put('a', "a");
map.put('b', "b");
map.put('c', "c");

verify(map).put(eq('c'), anyString());
verify(map).put(eq('a'), anyString());
verify(map).put(eq('b'), anyString());

Perhatikan bahwa verifikasi pertama bahkan tidak dalam urutan sehubungan dengan pemanggilan yang sebenarnya.

Selain itu, saya akan menyarankan Anda untuk tidak mengejek tipe yang tidak Anda miliki, misalnya tipe struts.

[EDIT @Brad]

Setelah menjalankan kode Brice (di atas) di IDE saya, saya dapat melihat bahwa saya telah menggunakan ActionError alih-alih ActionMessage, jadi itulah mengapa verifikasi () saya tidak cocok. Pesan kesalahan yang awalnya saya posting menyesatkan saya sehingga mengira itu adalah argumen pertama yang tidak cocok. Ternyata itu argumen kedua.

Jadi jawaban atas pertanyaan saya adalah

/** 
 * note that ActionMessageFactory.createErrorMessage() returns ActionMessage
 * and ActionError extends ActionMessage
 */
verify(errors).add(eq("exception.message"), any(ActionMessage.class));
verify(errors).add(eq("exception.detail"), any(ActionMessage.class));
Brice
sumber
1
Jangan mengerti apa yang ingin Anda katakan. Apakah urutan verifikasi itu penting? jika urutan verifikasi penting. Lalu mengapa di sini tersedia api InOrder?
Oleksandr Papchenko
Seperti yang tertulis di atas, perintah verifikasi tidak relevan; itulah mengapa ada InOrder.
Brice
12

Anda dapat menggunakan Mockito.atLeastOnce()yang memungkinkan Mockito lulus ujian meskipun mockObject itu akan dipanggil berkali-kali.

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));
sendon1982
sumber
1

1) Beritahu Mokito jumlah panggilan yang diharapkan.

2) Beritahu Mokito berapa kali diharapkan setiap kombinasi parameter.

verify(errors, times(2)).add(any(), any(ActionMessage.class));

verify(errors, atLeastOnce()).add(eq("exception.message"), any());
verify(errors, atLeastOnce()).add(eq("exception.detail"), any());
epox
sumber
0

Dengan cara yang mirip dengan @ sendon1928 kita dapat menggunakan:

Mockito.times(wantedInvocationCount)

untuk memastikan metode dipanggil berkali-kali (solusi yang lebih disukai menurut saya). Setelah itu, kita bisa menelepon

Mockito.verifyNoMoreInteractions(mock)

Untuk memastikan bahwa tiruan itu tidak digunakan lebih lanjut dalam konteks apa pun. Contoh lengkap:

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(2));

Mockito.verifyNoMoreInteractions(mockObject)
Michał Powłoka
sumber