Menggunakan Mockito ArgumentCaptor

1. Ikhtisar

Dalam tutorial ini, kami akan membahas kasus penggunaan umum penggunaan Mockito ArgumentCaptor dalam pengujian unit kami.

Atau, untuk lainnya Mockito.verify kasus penggunaan, lihat Mockito kami Verifikasi Cookbook.

2. Menggunakan ArgumentCaptor

ArgumentCaptor memungkinkan kita untuk menangkap argumen yang diteruskan ke metode untuk memeriksanya. Ini sangat berguna ketika kita tidak dapat mengakses argumen di luar metode yang ingin kita uji.

Misalnya, pertimbangkan kelas EmailService dengan metode kirim yang ingin kami uji:

public class EmailService { private DeliveryPlatform platform; public EmailService(DeliveryPlatform platform) { this.platform = platform; } public void send(String to, String subject, String body, boolean html) { Format format = Format.TEXT_ONLY; if (html) { format = Format.HTML; } Email email = new Email(to, subject, body); email.setFormat(format); platform.deliver(email); } ... }

Di EmailService . send , perhatikan bagaimana platform.deliver menggunakan Email baru sebagai argumen. Sebagai bagian dari pengujian kami, kami ingin memeriksa bahwa bidang format dari Email baru disetel ke Format.HTML . Untuk melakukan ini, kita perlu menangkap dan memeriksa argumen yang diteruskan ke platform.deliver .

Mari kita lihat bagaimana kita bisa menggunakan ArgumentCaptor untuk membantu kita.

2.1. Siapkan Tes Unit

Pertama, mari buat kelas pengujian unit kita:

@RunWith(MockitoJUnitRunner.class) public class EmailServiceUnitTest { @Mock DeliveryPlatform platform; @InjectMocks EmailService emailService; ... }

Kami menggunakan anotasi @Mock untuk meniru DeliveryPlatform , yang secara otomatis dimasukkan ke dalam Layanan Email kami dengan anotasi @InjectMocks . Lihat artikel Anotasi Mockito kami untuk detail lebih lanjut.

2.2. Tambahkan Bidang ArgumentCaptor

Kedua, mari tambahkan bidang ArgumentCaptor baru dengan tipe Email untuk menyimpan argumen yang ditangkap:

@Captor ArgumentCaptor emailCaptor;

2.3. Tangkap Argumen

Ketiga, mari gunakan Mockito.verify dengan ArgumentCaptor untuk menangkap Email :

Mockito.verify(platform).deliver(emailCaptor.capture());

Kita kemudian bisa mendapatkan nilai yang ditangkap dan menyimpannya sebagai objek Email baru :

Email emailCaptorValue = emailCaptor.getValue();

2.4. Periksa Nilai yang Diambil

Terakhir, mari kita lihat keseluruhan pengujian dengan assert untuk memeriksa objek Email yang diambil :

@Test public void whenDoesSupportHtml_expectHTMLEmailFormat() { String to = "[email protected]"; String subject = "Using ArgumentCaptor"; String body = "Hey, let'use ArgumentCaptor"; emailService.send(to, subject, body, true); Mockito.verify(platform).deliver(emailCaptor.capture()); Email value = emailCaptor.getValue(); assertEquals(Format.HTML, value.getFormat()); }

3. Menghindari Stubbing

Meskipun kita bisa menggunakan ArgumentCaptor dengan stubbing , umumnya kita harus menghindari melakukannya. Untuk memperjelas, di Mockito, ini biasanya berarti menghindari penggunaan ArgumentCaptor dengan Mockito.when . Dengan stubbing, sebagai gantinya kita harus menggunakan ArgumentMatcher .

Mari kita lihat beberapa alasan mengapa kita harus menghindari stubbing.

3.1. Keterbacaan Tes Menurun

Pertama, pertimbangkan tes sederhana :

Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key"); Mockito.when(platform.authenticate(Mockito.eq(credentials))) .thenReturn(AuthenticationStatus.AUTHENTICATED); assertTrue(emailService.authenticatedSuccessfully(credentials));

Di sini, kami menggunakan Mockito.eq (kredensial) untuk menentukan kapan tiruan harus mengembalikan sebuah objek.

Selanjutnya, pertimbangkan pengujian yang sama menggunakan ArgumentCaptor sebagai gantinya:

Credentials credentials = new Credentials("baeldung", "correct_password", "correct_key"); Mockito.when(platform.authenticate(credentialsCaptor.capture())) .thenReturn(AuthenticationStatus.AUTHENTICATED); assertTrue(emailService.authenticatedSuccessfully(credentials)); assertEquals(credentials, credentialsCaptor.getValue());

Berbeda dengan pengujian pertama, perhatikan bagaimana kita harus melakukan pernyataan tambahan pada baris terakhir untuk melakukan hal yang sama seperti Mockito.eq (kredensial) .

Terakhir, perhatikan bagaimana tidak jelas apa yang dirujuk credentialsCaptor.capture () . Ini karena kita harus membuat captor di luar garis tempat kita menggunakannya, yang mengurangi keterbacaan.

3.2. Lokalisasi Cacat yang Dikurangi

Alasan lainnya adalah jika emailService.authenticatedSuccessfully tidak memanggil platform.authenticate , kita akan mendapatkan pengecualian:

org.mockito.exceptions.base.MockitoException: No argument value was captured!

Ini karena metode stub kami belum menangkap argumen. Namun, masalah sebenarnya bukan pada pengujian kami itu sendiri, tetapi metode sebenarnya yang kami uji.

Dengan kata lain, itu salah mengarahkan kita ke pengecualian dalam pengujian, sedangkan cacat sebenarnya ada dalam metode yang kita uji.

4. Kesimpulan

Dalam tutorial singkat ini, kami melihat kasus penggunaan umum menggunakan ArgumentCaptor . Kami juga melihat alasan menghindari penggunaan ArgumentCaptor dengan stubbing. Seperti biasa, semua contoh kode kami tersedia di GitHub.