Perbedaan antara menggunakan MockMvc dengan SpringBootTest dan Menggunakan WebMvcTest

96

Saya baru mengenal Spring Boot dan mencoba memahami cara kerja pengujian di SpringBoot. Saya agak bingung tentang apa perbedaan antara dua cuplikan kode berikut:

Cuplikan kode 1:

@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class HelloControllerApplicationTest {
    @Autowired    
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }
}

Tes ini menggunakan @WebMvcTestanotasi yang saya yakini untuk pengujian potongan fitur dan hanya menguji lapisan MVC dari aplikasi web.

Cuplikan kode 2:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void getHello() throws Exception {
    mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(content().string(equalTo("Greetings from Spring Boot!")));
    }
}

Tes ini menggunakan @SpringBootTestanotasi dan a MockMvc. Jadi, apa bedanya dengan cuplikan kode 1? Apa yang dilakukannya secara berbeda?

Edit: Menambahkan Cuplikan Kode 3 (Temukan ini sebagai contoh pengujian integrasi dalam dokumentasi Spring)

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
public class HelloControllerIT {
    
    @LocalServerPort private int port;
    private URL base;
    
    @Autowired private TestRestTemplate template;
    
    @Before public void setUp() throws Exception {
        this.base = new URL("http://localhost:" + port + "/");
    }
    
    @Test public void getHello() throws Exception {
        ResponseEntity < String > response = template.getForEntity(base.toString(), String.class);
        assertThat(response.getBody(), equalTo("Greetings from Spring Boot!"));
    }
}
Revansha
sumber

Jawaban:

88

@SpringBootTestadalah anotasi tes umum. Jika Anda mencari sesuatu yang melakukan hal yang sama sebelum 1.4, itulah yang harus Anda gunakan. Itu tidak menggunakan pemotongan sama sekali yang berarti itu akan memulai konteks aplikasi lengkap Anda dan tidak menyesuaikan pemindaian komponen sama sekali.

@WebMvcTesthanya akan memindai pengontrol yang telah Anda tetapkan dan infrastruktur MVC. Itu dia. Jadi, jika pengontrol Anda memiliki beberapa ketergantungan pada kacang lain dari lapisan layanan Anda, pengujian tidak akan dimulai sampai Anda memuat konfigurasi itu sendiri atau memberikan tiruan untuknya. Ini jauh lebih cepat karena kami hanya memuat sebagian kecil dari aplikasi Anda. Anotasi ini menggunakan pemotongan.

Membaca dokumen mungkin akan membantu Anda juga.

Stephane Nicoll
sumber
Terima kasih banyak telah menanggapi !!. Jadi jika saya memahami Anda dengan benar, artinya kedua cuplikan kode tersebut hanya menguji bagian MVC dari aplikasi tersebut. Tetapi potongan kode 1 memuat konteks aplikasi lengkap sedangkan potongan kode 2 hanya memindai pengontrol. Apakah ini benar? Dapatkah cuplikan kode 1 dianggap sebagai pengujian unit untuk menguji pengontrol?
Revansha
1
Tidak, itu tidak benar. SpringBootTestsedang memuat aplikasi lengkap Anda (untuk beberapa perluasan, secara default ini tidak akan memulai penampung tersemat jika ada yang tersedia, untuk itulah webEnvironmentada). Saya tidak akan mengatakan itu @SpringBootTestadalah tes unit pengontrol tetapi lebih merupakan tes integrasi, sungguh. WebMvcTestbenar-benar merupakan pengujian unit pengontrol Anda dalam arti bahwa jika memiliki ketergantungan, Anda harus menyediakannya sendiri (baik konfigurasi atau semacam tiruan).
Stephane Nicoll
Sekali lagi terima kasih telah menanggapi. Saya telah mengedit pertanyaan dan menambahkan potongan kode 3. Anda menyebutkan bahwa penjelasan @SpringBootTest lebih banyak digunakan untuk pengujian integrasi. Saya yakin Snippet 3 menunjukkan ini. Jadi jika pengujian integrasi dilakukan seperti di Snippet 3 lalu apa yang dilakukan Snippet 2? Snippet 2 menggunakan anotasi SpringBootTest dan lingkungan tiruan (Nilai default dari atribut wenEnvironment). Selain itu, cuplikan 3 memulai server tertanam dan benar-benar melakukan panggilan HTTP sedangkan cuplikan 2 tidak melakukan ini. Jadi mempertimbangkan ini, tidak bisakah potongan 2 dianggap sebagai pengujian unit?
Revansha
4
Saya tidak yakin kita akan menyelesaikan masalah ini di sini. Mungkin gitter? Hal yang sepertinya selalu Anda lewatkan adalah konteks aplikasi yang SpringBootTestdan WebMvcTestbuat sangat berbeda. Yang pertama memuat aplikasi SELURUH Anda dan mengaktifkan SEMUA konfigurasi otomatis sedangkan yang terakhir hanya mengaktifkan Spring Mvc dan tidak memindai apa pun kecuali HelloController. Itu semua tergantung apa yang Anda maksud dengan tes unit. Tapi itulah perbedaannya.
Stephane Nicoll
Terimakasih atas tanggapan Anda. Itu sangat membantu saya. Sekarang saya mengerti mengapa pengujian saya dapat berjalan dengan SpringBootTest tetapi pengecualian saat WebMvcTest. Terima kasih banyak lagi.
Alps1992
69

Anotasi @SpringBootTest memberi tahu Spring Boot untuk pergi dan mencari kelas konfigurasi utama (misalnya dengan @SpringBootApplication), dan menggunakannya untuk memulai konteks aplikasi Spring. SpringBootTest memuat aplikasi lengkap dan menyuntikkan semua kacang yang bisa jadi lambat.

@WebMvcTest - untuk menguji lapisan pengontrol dan Anda perlu menyediakan dependensi yang tersisa yang diperlukan menggunakan Objek Mock.

Beberapa penjelasan di bawah ini untuk referensi Anda.

Menguji irisan aplikasi Kadang-kadang Anda ingin menguji “irisan” sederhana dari aplikasi daripada mengonfigurasi keseluruhan aplikasi secara otomatis. Spring Boot 1.4 memperkenalkan 4 anotasi pengujian baru:

@WebMvcTest - for testing the controller layer
@JsonTest - for testing the JSON marshalling and unmarshalling
@DataJpaTest - for testing the repository layer
@RestClientTests - for testing REST clients

Lihat informasi lebih lanjut: https://spring.io/guides/gs/testing-web/

RoshanKumar Mutha
sumber
Berikut ini tautan ke Sping Boot Reference - Uji Anotasi Konfigurasi Otomatis . Ada lebih dari empat @ roshankumar-mutha yang telah terdaftar di sini. Tautan ke panduan memulai tidak membahas irisan ini secara mendalam.
George Pantazes
15

Pengujian MVC dimaksudkan untuk mencakup bagian pengontrol aplikasi Anda saja. Permintaan dan tanggapan HTTP diolok-olok sehingga koneksi yang sebenarnya tidak dibuat. Di sisi lain, saat Anda menggunakan @SpringBootTest, semua konfigurasi untuk konteks aplikasi web dimuat dan koneksi akan melalui server web yang sebenarnya. Dalam hal ini, Anda tidak menggunakan MockMvckacang melainkan standar RestTemplate(atau alternatif baru TestRestTemplate).

Jadi, kapan kita harus memilih salah satu? @WebMvcTestdimaksudkan untuk menguji pengontrol secara terpadu dari sisi server. @SpringBootTest, di sisi lain, harus digunakan untuk pengujian integrasi, ketika Anda ingin berinteraksi dengan aplikasi dari sisi klien.

Itu tidak berarti bahwa Anda tidak dapat menggunakan ejekan dengan @SpringBootTest; jika Anda sedang menulis pengujian integrasi, itu mungkin masih diperlukan. Bagaimanapun, lebih baik tidak menggunakannya hanya untuk pengujian unit pengontrol sederhana.

sumber - Mempelajari Layanan Mikro dengan Spring Boot

Gautam Tadigoppula
sumber
1
Saya tidak mengerti mengapa jawaban ini di-upvoted .. Saat Anda menggunakan @SpringBootTest, server web yang sebenarnya tidak dijalankan kecuali Anda juga memiliki webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT(atau a DEFINED_PORT) dan koneksi tidak melalui server web yang sebenarnya. Default untuk @SpringBootTestadalah WebEnvironment.MOCK.
Koray Tugay