Sự khác biệt giữa sử dụng MockMvc với SpringBootTest và sử dụng WebMvcTest


97

Tôi mới sử dụng Spring Boot và đang cố gắng hiểu cách kiểm tra hoạt động trong SpringBoot. Tôi hơi bối rối về sự khác biệt giữa hai đoạn mã sau:

Đoạn mã 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!")));
    }
}

Thử nghiệm này sử dụng @WebMvcTestchú thích mà tôi tin là để kiểm tra phần tính năng và chỉ kiểm tra lớp MVC của một ứng dụng web.

Đoạn mã 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!")));
    }
}

Kiểm tra này sử dụng @SpringBootTestchú thích và a MockMvc. Vậy đoạn mã này khác với đoạn mã 1 như thế nào? Điều này làm gì khác?

Chỉnh sửa: Thêm đoạn mã 3 (Tìm thấy đây là một ví dụ về thử nghiệm tích hợp trong tài liệu 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!"));
    }
}

Câu trả lời:


88

@SpringBootTestlà chú thích kiểm tra chung. Nếu bạn đang tìm kiếm thứ gì đó hoạt động tương tự trước 1.4, thì đó là thứ bạn nên sử dụng. Nó hoàn toàn không sử dụng tính năng cắt , có nghĩa là nó sẽ khởi động ngữ cảnh ứng dụng đầy đủ của bạn và hoàn toàn không tùy chỉnh quét thành phần.

@WebMvcTestsẽ chỉ quét bộ điều khiển bạn đã xác định và cơ sở hạ tầng MVC. Đó là nó. Vì vậy, nếu bộ điều khiển của bạn có một số phụ thuộc vào các bean khác từ lớp dịch vụ của bạn, thì quá trình kiểm tra sẽ không bắt đầu cho đến khi bạn tự tải cấu hình đó hoặc cung cấp một mô hình cho nó. Điều này nhanh hơn nhiều vì chúng tôi chỉ tải một phần nhỏ ứng dụng của bạn. Chú thích này sử dụng phương pháp cắt.

Đọc tài liệu có lẽ cũng sẽ giúp bạn.


Cảm ơn rất nhiều vì đã phản hồi !!. Vì vậy, nếu tôi hiểu bạn một cách chính xác, điều đó có nghĩa là cả hai đoạn mã chỉ kiểm tra phần MVC của ứng dụng. Nhưng đoạn mã tcode 1 tải toàn bộ ngữ cảnh ứng dụng trong khi đoạn mã 2 chỉ quét bộ điều khiển. Điều này có chính xác? Đoạn mã 1 có thể được coi là một bài kiểm tra đơn vị để kiểm tra bộ điều khiển không?
Revansha

1
Không, nó không chính xác. SpringBootTestđang tải ứng dụng đầy đủ của bạn (đối với một số phần mở rộng, theo mặc định, nó sẽ không khởi động vùng chứa được nhúng nếu có sẵn, đó là những gì webEnvironmentcó sẵn). Tôi sẽ không nói đó @SpringBootTestlà một bài kiểm tra đơn vị của bộ điều khiển mà thực sự là một bài kiểm tra tích hợp. WebMvcTestthực sự là một bài kiểm tra đơn vị của bộ điều khiển của bạn theo nghĩa là nếu nó có sự phụ thuộc, bạn sẽ phải tự cung cấp chúng (cấu hình hoặc một mô hình nào đó).
Stephane Nicoll

Cảm ơn một lần nữa vì đã phản hồi. Tôi đã chỉnh sửa câu hỏi và thêm đoạn mã 3. Bạn đã đề cập rằng chú thích @SpringBootTest được sử dụng nhiều hơn để kiểm tra tích hợp. Tôi tin rằng Snippet 3 thể hiện điều này. Vì vậy, nếu kiểm thử tích hợp được thực hiện như trong Snippet 3 thì Snippet 2 sẽ làm gì? Đoạn mã 2 sử dụng chú thích SpringBootTest và một môi trường giả (Giá trị mặc định của thuộc tính wenEnosystem). Ngoài ra, đoạn mã 3 khởi động máy chủ nhúng và thực hiện các cuộc gọi HTTP thực sự trong khi đoạn mã 2 không thực hiện điều này. Vì vậy, xem xét điều này, không thể coi đoạn mã 2 là một bài kiểm tra đơn vị?
Revansha

4
Tôi không chắc chúng ta sẽ giải quyết vấn đề này ở đây. Có lẽ gitter? Điều mà bạn dường như thường xuyên bỏ lỡ là bối cảnh ứng dụng tạo SpringBootTestWebMvcTesttạo ra rất khác nhau. Cái trước tải toàn bộ ứng dụng của bạn và bật TẤT CẢ các cấu hình tự động trong khi cái sau chỉ bật Spring Mvc và không quét bất cứ thứ gì ngoại trừ HelloController. Rốt cuộc, tất cả phụ thuộc vào ý bạn của bài kiểm tra đơn vị. Nhưng đó là sự khác biệt.
Stephane Nicoll

Cám ơn phản hồi của bạn. Điều đó rất hữu ích cho tôi. Bây giờ tôi hiểu tại sao thử nghiệm của tôi có thể chạy với SpringBootTest nhưng ngoại lệ khi WebMvcTest. Cảm ơn rất nhiều một lần nữa.
Alps1992

69

Chú thích @SpringBootTest yêu cầu Spring Boot đi và tìm kiếm một lớp cấu hình chính (ví dụ: một lớp có @SpringBootApplication) và sử dụng lớp đó để bắt đầu bối cảnh ứng dụng Spring. SpringBootTest tải ứng dụng hoàn chỉnh và đưa tất cả các bean có thể chạy chậm.

@WebMvcTest - để kiểm tra lớp bộ điều khiển và bạn cần cung cấp các phần phụ thuộc còn lại được yêu cầu bằng cách sử dụng Đối tượng Mock.

Thêm một vài chú thích bên dưới để bạn tham khảo.

Kiểm tra các phần của ứng dụng Đôi khi bạn muốn kiểm tra một “phần” đơn giản của ứng dụng thay vì tự động cấu hình toàn bộ ứng dụng. Spring Boot 1.4 giới thiệu 4 chú thích thử nghiệm mới:

@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

Tham khảo thêm thông tin: https://spring.io/guides/gs/testing-web/


Đây là một liên kết đến Sping Boot Reference - Test Auto-configuration Annotations . Không chỉ có bốn @ roshankumar-mutha được liệt kê ở đây. Liên kết đến hướng dẫn bắt đầu không trình bày sâu về các phần này.
George Pantazes

15

Các bài kiểm tra MVC nhằm mục đích chỉ bao gồm phần điều khiển của ứng dụng của bạn. Các yêu cầu và phản hồi HTTP bị giả mạo để các kết nối thực không được tạo. Mặt khác, khi bạn sử dụng @SpringBootTest, tất cả cấu hình cho ngữ cảnh ứng dụng web được tải và các kết nối sẽ đi qua máy chủ web thực. Trong trường hợp đó, bạn không sử dụng MockMvcbean mà RestTemplatethay vào đó là một tiêu chuẩn (hoặc thay thế mới TestRestTemplate).

Vì vậy, khi nào chúng ta nên chọn cái này hay cái kia? @WebMvcTestnhằm mục đích kiểm tra đơn nhất bộ điều khiển từ phía máy chủ. @SpringBootTest, mặt khác, nên được sử dụng cho các bài kiểm tra tích hợp, khi bạn muốn tương tác với ứng dụng từ phía máy khách.

Điều đó không có nghĩa là bạn không thể sử dụng mocks với @SpringBootTest; nếu bạn đang viết một bài kiểm tra tích hợp, điều đó vẫn có thể cần thiết. Trong mọi trường hợp, tốt hơn là không nên sử dụng nó chỉ để kiểm tra đơn vị của bộ điều khiển đơn giản.

source - Học Microservices với Spring Boot


2
Tôi không hiểu tại sao câu trả lời này được ủng hộ .. Khi bạn sử dụng @SpringBootTest, máy chủ web thực không được khởi động trừ khi bạn cũng có webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT(hoặc a DEFINED_PORT) và các kết nối không đi qua máy chủ web thực. Giá trị mặc định @SpringBootTestWebEnvironment.MOCK.
Koray Tugay
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.