MockMvc'yi SpringBootTest ile kullanmak ile WebMvcTest'i kullanmak arasındaki fark


96

Spring Boot'ta yeniyim ve SpringBoot'ta testin nasıl çalıştığını anlamaya çalışıyorum. Aşağıdaki iki kod parçacığı arasındaki farkın ne olduğu konusunda biraz kafam karıştı:

Kod pasajı 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!")));
    }
}

Bu test, @WebMvcTestözellik dilim testi için olduğuna inandığım açıklamayı kullanıyor ve yalnızca bir web uygulamasının MVC katmanını test ediyor.

Kod parçacığı 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!")));
    }
}

Bu test, @SpringBootTestek açıklamayı ve a MockMvc. Peki bunun kod parçacığı 1'den farkı nedir? Bu neyi farklı yapıyor?

Düzenleme: Kod Parçacığı Ekleme 3 (Bunu, Bahar belgelerinde entegrasyon testi örneği olarak buldum)

@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!"));
    }
}

Yanıtlar:


88

@SpringBootTestgenel test açıklamasıdır. 1.4'ten önce aynı şeyi yapan bir şey arıyorsanız, kullanmanız gereken budur. Dilimlemeyi hiç kullanmaz , bu da tam uygulama bağlamınızı başlatacağı ve bileşen taramayı hiç özelleştirmeyeceği anlamına gelir.

@WebMvcTestsadece tanımladığınız denetleyiciyi ve MVC altyapısını tarayacak. Bu kadar. Dolayısıyla, denetleyicinizin hizmet katmanınızdaki diğer çekirdeklere bağımlılığı varsa, test, siz bu yapılandırmayı kendiniz yükleyene veya bunun için bir örnek sağlayana kadar başlamaz. Uygulamanızın yalnızca küçük bir bölümünü yüklediğimiz için bu çok daha hızlıdır. Bu açıklama dilimlemeyi kullanır.

Belgeyi okumak muhtemelen size de yardımcı olacaktır.


Cevap verdiğiniz için çok teşekkürler !! Sizi doğru anladıysam, bunun anlamı, her iki kod parçacığının da uygulamanın yalnızca MVC bölümünü test etmesidir. Ancak tcode parçacığı 1 tüm uygulama içeriğini yüklerken kod parçacığı 2 yalnızca denetleyiciyi tarar. Bu doğru mu? Kod parçacığı 1, denetleyiciyi test etmek için bir birim testi olarak kabul edilebilir mi?
Revansha

1
Hayır bu doğru değil. SpringBootTesttam uygulamanızı yüklüyor (mevcut bir tane varsa, bir dereceye kadar varsayılan olarak gömülü kapsayıcıyı başlatmaz webEnvironment, bunun için var). Bunun @SpringBootTestkontrolörün birim testi olduğunu söyleyemem, daha çok bir entegrasyon testi, gerçekten. WebMvcTestbağımlılık varsa, onlara kendiniz sağlamanız gerekeceği anlamında denetleyicinizin gerçekten bir birim testidir (bir yapılandırma veya bir tür sahte).
Stephane Nicoll

Cevap verdiğiniz için tekrar teşekkürler. Soruyu düzenledim ve kod parçacığını ekledim 3. @SpringBootTest ek açıklamasının daha çok entegrasyon testi için kullanıldığından bahsettiniz. Snippet 3'ün bunu gösterdiğine inanıyorum. Peki entegrasyon testi Snippet 3'teki gibi yapılırsa Snippet 2 ne yapar? Snippet 2, SpringBootTest ek açıklamasını ve bir sahte ortam kullanır (wenEnvironment özniteliğinin varsayılan değeri). Ayrıca, snippet 3, katıştırılmış sunucuyu başlatır ve gerçekten HTTP çağrıları yapar, oysa snippet 2 bunu yapmaz. Öyleyse, bunu göz önünde bulundurursak, pasaj 2 bir birim testi olarak kabul edilemez mi?
Revansha

4
Bunu burada çözeceğimizden emin değilim. Belki gitter? Sürekli gözden kaçırdığınız şey, yarattığı SpringBootTestve WebMvcTestyarattığı uygulama bağlamının büyük ölçüde farklı olmasıdır. İlki, BÜTÜN uygulamanızı yükler ve TÜM otomatik yapılandırmaları etkinleştirirken, ikincisi yalnızca Spring Mvc'yi etkinleştirir ve başka hiçbir şeyi taramaz HelloController. Her şey sonuçta bir birim testi ile ne demek istediğine bağlı. Ama fark bu.
Stephane Nicoll

Cevabınız için teşekkürler. Bu benim için çok yardımcı oldu. Şimdi testimin neden SpringBootTest ile çalışabildiğini ancak WebMvcTest olduğunda istisna olduğunu anlıyorum. Tekrar çok teşekkürler.
Alps1992

69

@SpringBootTest açıklama, Spring Boot'a gidip bir ana yapılandırma sınıfını (örneğin @SpringBootApplication içeren bir sınıf) aramasını ve bunu bir Spring uygulama bağlamı başlatmak için kullanmasını söyler. SpringBootTest, eksiksiz uygulamayı yükler ve yavaş olabilecek tüm çekirdekleri enjekte eder.

@WebMvcTest - denetleyici katmanını test etmek için ve Mock Objects kullanarak gereken kalan bağımlılıkları sağlamanız gerekir.

Referans için aşağıda birkaç ek açıklama daha var.

Uygulama dilimlerini test etme Bazen tüm uygulamayı otomatik olarak yapılandırmak yerine uygulamanın basit bir "dilim" ini test etmek istersiniz. Spring Boot 1.4, 4 yeni test ek açıklaması sunuyor:

@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

Daha fazla bilgi için bakın: https://spring.io/guides/gs/testing-web/


İşte Sping Önyükleme Referansı - Otomatik Yapılandırma Ek Açıklamalarını Test Et'e bir bağlantı . Burada listelenen dört @ roshankumar-mutha'dan daha fazlası var. Başlangıç ​​kılavuzunun bağlantısı bu dilimleri derinlemesine kapsamaz.
George Pantazes

15

MVC testleri, uygulamanızın yalnızca kontrolör parçasını kapsamayı amaçlamaktadır. HTTP istekleri ve yanıtları alay edilir, böylece gerçek bağlantılar oluşturulmaz. Öte yandan, kullandığınızda @SpringBootTest, web uygulaması içeriği için tüm konfigürasyon yüklenir ve bağlantılar gerçek web sunucusundan geçer. Bu durumda, MockMvcfasulyeyi değil, RestTemplatebunun yerine bir standart (veya yeni alternatifi TestRestTemplate) kullanırsınız.

Öyleyse, birini veya diğerini ne zaman seçmeliyiz? @WebMvcTestdenetleyiciyi sunucu tarafından tek birim olarak test etmek için tasarlanmıştır. @SpringBootTestuygulama ile istemci tarafında etkileşim kurmak istediğinizde ise entegrasyon testleri için kullanılmalıdır.

Bu, alayları kullanamayacağınız anlamına gelmez @SpringBootTest; Bir entegrasyon testi yazıyorsanız, bu yine de gerekli olabilir. Her durumda, onu sadece basit bir kontrolörün birim testi için kullanmamak daha iyidir.

kaynak - Spring Boot ile Mikro Hizmetleri Öğrenme


1
Bu cevabın neden yükseltildiğini anlamıyorum .. Kullandığınız zaman, sizde (veya a ) @SpringBootTestolmadıkça gerçek bir web sunucusu başlatılmaz ve bağlantılar gerçek web sunucusundan geçmez. İçin varsayılan DİR . webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORTDEFINED_PORT@SpringBootTestWebEnvironment.MOCK
Koray Tugay
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.