Різниця між використанням MockMvc із SpringBootTest та використанням WebMvcTest


97

Я новачок у Spring Boot і намагаюся зрозуміти, як працює тестування в SpringBoot. Я трохи збентежений, яка різниця між двома наступними фрагментами коду:

Фрагмент коду 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!")));
    }
}

Цей тест використовує @WebMvcTestанотацію, яка, на мою думку, призначена для тестування зрізів функцій, і тестує лише рівень MVC веб-програми.

Фрагмент коду 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!")));
    }
}

Цей тест використовує @SpringBootTestанотацію та a MockMvc. То чим це відрізняється від фрагмента коду 1? Що це робить інакше?

Редагувати: Додавання фрагмента коду 3 (Знайдено як приклад тестування інтеграції у весняній документації)

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

Відповіді:


88

@SpringBootTest- загальна анотація тесту. Якщо ви шукаєте щось, що робить те саме до 1.4, це саме те, що вам слід використовувати. У ньому взагалі не використовується нарізка, що означає, що він запустить ваш повний контекст програми і взагалі не налаштує сканування компонентів.

@WebMvcTestзбирається лише сканувати контролер, який ви визначили, та інфраструктуру MVC. Це воно. Отже, якщо ваш контролер має певну залежність від інших компонентів з вашого сервісного рівня, тест не розпочнеться, поки ви не завантажите цю конфігурацію самостійно або не надасте макет для неї. Це набагато швидше, оскільки ми завантажуємо лише крихітну частину вашого додатка. Ця анотація використовує нарізку.

Читання документа, мабуть, також має допомогти вам.


Велике спасибі за відповідь !!. Отже, якщо я вас правильно розумію, це означає, що обидва фрагменти коду перевіряють лише частину програми MVC. Але фрагмент tcode 1 завантажує повний контекст програми, тоді як фрагмент коду 2 сканує лише контролер. Це правильно? Чи можна фрагмент коду 1 розглядати як модульний тест для тестування контролера?
Revansha

1
Ні, це не правильно. SpringBootTestзавантажує ваш повний додаток (до певної міри, за замовчуванням він не запускає вбудований контейнер, якщо такий є, ось для чого webEnvironmentвін потрібен). Я б не сказав, що @SpringBootTestце модульний тест контролера, а насправді більше інтеграційний тест. WebMvcTestнасправді є модульним тестом вашого контролера в тому сенсі, що якщо він має залежність, вам доведеться надати їх самостійно (або конфігурацію, або макет якогось виду).
Стефан Ніколл

Ще раз спасибі за відповідь. Я відредагував запитання та додав фрагмент коду 3. Ви згадали, що анотація @SpringBootTest використовується більше для тестування інтеграції. Я вважаю, що фрагмент 3 це демонструє. Тож якщо інтеграційне тестування проводиться, як у фрагменті 3, то що робить фрагмент 2? Фрагмент 2 використовує анотацію SpringBootTest та макетне середовище (значення за замовчуванням атрибута wenEnvironment). Крім того, фрагмент 3 запускає вбудований сервер і робить справді виклики HTTP, тоді як фрагмент 2 цього не робить. Тож враховуючи це, чи не можна фрагмент 2 вважати одиничним тестом?
Реванша,

4
Я не впевнений, що ми збираємось це розібрати тут. Може, гіттер? Те, чого вам, здається, постійно не вистачає, полягає в тому, що контекст програми, який створюється SpringBootTestта WebMvcTestстворюється, сильно відрізняється. Перший завантажує вашу ЦІЛУ програму та включає ВСІ автоматичні конфігурації, тоді як другий включає лише Spring Mvc і не сканує нічого, крім HelloController. Все залежить від того, що ви зрештою маєте на увазі під юніт-тестом. Але в цьому різниця.
Стефан Ніколл

Дякую за Вашу відповідь. Це дуже корисно для мене. Тепер я розумію, чому мій тест може запускатися з SpringBootTest, але виняток коли WebMvcTest. Ще раз велике спасибі.
Alps1992

69

Анотація @SpringBootTest повідомляє Spring Boot піти шукати основний клас конфігурації (наприклад, такий, що має @SpringBootApplication) і використовувати його для запуску контексту програми Spring. SpringBootTest завантажує повну програму і вводить всі боби, які можуть бути повільними.

@WebMvcTest - для тестування рівня контролера вам потрібно надати решту залежностей, необхідних за допомогою Mock Objects.

Ще декілька анотацій нижче для довідки.

Тестування фрагментів програми Іноді вам хочеться протестувати простий “фрагмент” програми, замість того, щоб автоматично конфігурувати всю програму. Spring Boot 1.4 представляє 4 нові тестові анотації:

@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

Для отримання додаткової інформації зверніться: https://spring.io/guides/gs/testing-web/


Ось посилання на Sping Boot Reference - Test Auto-configuration Annotations . Тут є не тільки чотири перераховані @ roshankumar-mutha. Посилання на посібник із початку роботи не охоплює цих фрагментів поглиблено.
Джордж Пантазес,

15

Тести MVC призначені для охоплення лише частини контролера вашої програми. Запити та відповіді HTTP висміюються, тому реальні з'єднання не створюються. З іншого боку, коли ви використовуєте @SpringBootTest, вся конфігурація контексту веб-програми завантажується, а з'єднання проходять через справжній веб-сервер. У цьому випадку ви використовуєте не MockMvcбоб, а RestTemplateзамість нього стандартний (або нову альтернативу TestRestTemplate).

Отже, коли ми повинні вибрати те чи інше? @WebMvcTestпризначений для тестування контролера з боку сервера. @SpringBootTest, з іншого боку, слід використовувати для інтеграційних тестів, коли ви хочете взаємодіяти з додатком з боку клієнта.

Це не означає, що ви не можете використовувати насмішки @SpringBootTest; якщо ви пишете інтеграційний тест, це все одно може знадобитися. У будь-якому випадку, краще не використовувати його лише для простого модульного тесту контролера.

джерело - Навчання мікросервісів за допомогою Spring Boot


2
Я не розумію, чому ця відповідь схвалюється. Коли ви використовуєте @SpringBootTest, справжній веб-сервер не запускається, якщо у вас також немає webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT(або a DEFINED_PORT), і з'єднання не проходять через справжній веб-сервер. За замовчуванням для @SpringBootTestIS WebEnvironment.MOCK.
Корай Тугай,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.