Perbedaan antara @Mock, @MockBean dan Mockito.mock ()

147

Saat membuat tes dan mengejek dependensi, apa perbedaan antara ketiga pendekatan ini?

  1. @MockBean:

    @MockBean
    MyService myservice;
  2. @Mengejek:

    @Mock
    MyService myservice;
  3. Mockito.mock ()

    MyService myservice = Mockito.mock(MyService.class);
Doug
sumber

Jawaban:

198

Perpustakaan Mockito polos

import org.mockito.Mock;
...
@Mock
MyService myservice;

dan

import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);

berasal dari perpustakaan Mockito dan secara fungsional setara.
Mereka memungkinkan untuk mengejek kelas atau antarmuka dan untuk merekam dan memverifikasi perilaku di dalamnya.

Cara menggunakan anotasi lebih pendek, jadi lebih disukai dan sering disukai.


Perhatikan bahwa untuk mengaktifkan anotasi Mockito selama pelaksanaan pengujian, MockitoAnnotations.initMocks(this)metode statis harus dipanggil.
Untuk menghindari efek samping antara tes, disarankan untuk melakukannya sebelum setiap pelaksanaan tes:

@Before 
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

Cara lain untuk mengaktifkan anotasi Mockito adalah memberi anotasi pada kelas uji dengan @RunWithmenetapkan MockitoJUnitRunneryang mengerjakan tugas ini dan juga hal-hal berguna lainnya:

@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}

Perpustakaan Spring Boot yang membungkus perpustakaan Mockito

Ini memang kelas Spring Boot :

import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;

Kelas termasuk dalam spring-boot-testperpustakaan.

Memungkinkan untuk menambahkan mockito mock di Spring ApplicationContext.
Jika kacang, yang kompatibel dengan kelas yang dideklarasikan ada dalam konteks, itu menggantikannya dengan tiruan.
Jika bukan itu masalahnya, ia menambahkan tiruan dalam konteks sebagai kacang.

Referensi Javadoc:

Anotasi yang dapat digunakan untuk menambahkan tiruan ke Spring ApplicationContext.

...

Jika ada satu kacang tunggal dengan tipe yang sama yang didefinisikan dalam konteks akan digantikan oleh mock, jika tidak ada kacang yang ada didefinisikan yang baru akan ditambahkan.


Kapan menggunakan Mockito klasik / polos dan kapan digunakan @MockBeandari Spring Boot?

Tes unit dirancang untuk menguji komponen yang terpisah dari komponen lain dan pengujian unit juga memiliki persyaratan: menjadi secepat mungkin dalam hal waktu eksekusi karena pengujian ini dapat dilakukan setiap hari selusin kali pada mesin pengembang.

Konsekuensinya, berikut adalah pedoman sederhana:

Saat Anda menulis tes yang tidak memerlukan dependensi dari wadah Spring Boot, Mockito klasik / polos adalah cara untuk mengikuti: cepat dan mendukung isolasi komponen yang diuji.
Jika pengujian Anda harus bergantung pada wadah Boot Musim Semi dan Anda juga ingin menambahkan atau mengejek salah satu wadah kacang: @MockBeandari Boot Musim Semi adalah caranya.


Penggunaan khas Boot Musim Semi @MockBean

Saat kami menulis kelas uji yang dijelaskan dengan @WebMvcTest(uji web slice).

Dokumentasi Spring Boot merangkum dengan sangat baik:

Seringkali @WebMvcTestakan terbatas pada pengontrol tunggal dan digunakan bersama dengan @MockBeanuntuk menyediakan implementasi tiruan untuk kolaborator yang diperlukan.

Berikut ini sebuah contoh:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private FooService fooServiceMock;

    @Test
    public void testExample() throws Exception {
         Foo mockedFoo = new Foo("one", "two");

         Mockito.when(fooServiceMock.get(1))
                .thenReturn(mockedFoo);

         mvc.perform(get("foos/1")
            .accept(MediaType.TEXT_PLAIN))
            .andExpect(status().isOk())
            .andExpect(content().string("one two"));
    }

}
davidxxx
sumber
4
Apakah menggunakan @MockBean membuat salinan kacang dan menyuntikkannya ke ApplicationContext? Atau mocked bean akan memiliki semua metodenya sebagai null? Jika semua metode ini null, bisakah saya mematikannya seperti yang dapat saya lakukan menggunakan @Mock?
Doug
6
Seperti yang dijelaskan, menggunakan @MockBeanakan menggantikan kacang dalam konteks aplikasi jika kacang menyatakan jenis yang sama sudah didefinisikan dalam konfigurasi Spring Anda. Dan injeksi dilakukan di kelas di mana Anda mendeklarasikan @MockBean.mekanisme DI bekerja dengan cara ini: Anda mendaftarkan objek dalam konteks DI dan kemudian Anda bisa menyuntikkan objek yang dirujuk dalam konteks Spring di kelas tertentu. Anda tidak menyuntikkan objek dalam konteks DI.
davidxxx
13

Pada akhirnya mudah dijelaskan. Jika Anda hanya melihat javadocs dari anotasi Anda akan melihat perbedaannya:

@Mock: ( org.mockito.Mock)

Tandai bidang sebagai tiruan.

  • Mengizinkan pembuatan tulisan tiruan steno.
  • Meminimalkan kode pembuatan tiruan berulang-ulang.
  • Jadikan kelas ujian lebih mudah dibaca.
  • Membuat kesalahan verifikasi lebih mudah dibaca karena nama bidang digunakan untuk mengidentifikasi tiruan.

@MockBean: ( org.springframework.boot.test.mock.mockito.MockBean)

Anotasi yang dapat digunakan untuk menambahkan tiruan ke Spring ApplicationContext. Dapat digunakan sebagai anotasi tingkat kelas atau pada bidang di salah satu @Configurationkelas, atau kelas uji yang ada@RunWith SpringRunner.

Mock dapat didaftarkan berdasarkan jenis atau nama kacang. Kacang tunggal apa pun yang ada dengan jenis yang sama yang ditentukan dalam konteks akan diganti oleh tiruan, jika tidak ada kacang yang ditetapkan, maka kacang baru akan ditambahkan.

Ketika @MockBeandigunakan di lapangan, serta terdaftar dalam konteks aplikasi, tiruan juga akan disuntikkan ke lapangan.

Mockito.mock ()

Itu hanya representasi dari @Mock.

Patrick
sumber
5
Jangan lupa bahwa @Mock membutuhkan MockitoRunner atau initMock yang dipanggil secara manual.
Florian Schaetz
4
Apakah satu-satunya perbedaan antara @MockBeandan @Mockyang satu akan menyuntikkan mock ke dalam Spring ApplicationContextdan yang lain tidak?
Doug
3
@Dougou meringkasnya dengan baik tetapi orang harus ingat bahwa MockBean adalah bagian dari Spring Boot
comiventor