Ответ
Для тестирования контроллеров Spring используется комбинация JUnit 5, Spring Test модуля и Mockito.
1. Тестирование слоя контроллера изолированно (@WebMvcTest):
Загружается только веб-слой контекста, все зависимости контроллера мокаются.
@WebMvcTest(UserController.class) // Загружаем только контроллер и MVC инфраструктуру
class UserControllerSliceTest {
@Autowired
private MockMvc mockMvc; // Главный инструмент для имитации запросов
@MockBean
private UserService userService; // Зависимость контроллера заменяется mock-объектом
@Test
void getUserById_ShouldReturnUser() throws Exception {
// Given
User mockUser = new User(1L, "Alice");
when(userService.findById(1L)).thenReturn(Optional.of(mockUser));
// When & Then
mockMvc.perform(get("/api/users/1")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1L))
.andExpect(jsonPath("$.name").value("Alice"));
verify(userService).findById(1L); // Проверяем вызов сервиса
}
}
2. Интеграционное тестирование (@SpringBootTest):
Загружается полный контекст приложения. Используется TestRestTemplate или WebTestClient для реальных HTTP-вызовов.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void getUserById_Integration() {
ResponseEntity<User> response = restTemplate.getForEntity("/api/users/1", User.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody().getName()).isNotNull();
}
}
Ключевые аннотации: @WebMvcTest (для срезов), @SpringBootTest (для интеграции), @MockBean (для моков в контексте Spring).
Ответ 18+ 🔞
Да ты посмотри, какая хуйня творится в мире тестирования контроллеров! Ну, типа, чтобы не писать говнокод, который потом развалится от первого чиха, надо их проверять. И для этого, блядь, есть целая связка: JUnit 5, этот Spring Test и Mockito, который всех на блюдечке подвезёт.
1. Тестируем контроллер, как будто он один такой умный в вакууме (@WebMvcTest):
Тут поднимается только веб-слой, всё остальное — в пизду, заменяется заглушками.
@WebMvcTest(UserController.class) // Тащим в память только этот контроллер и всю его MVC-обвязку, ебать
class UserControllerSliceTest {
@Autowired
private MockMvc mockMvc; // Эта штука будет притворяться браузером и слать запросы, хитрая жопа
@MockBean
private UserService userService; // А сервис наш — муляж, мартышлюшка, которая будет говорить то, что мы скажем
@Test
void getUserById_ShouldReturnUser() throws Exception {
// Допустим
User mockUser = new User(1L, "Alice");
when(userService.findById(1L)).thenReturn(Optional.of(mockUser)); // Говорим муляжу: «Вот, на, верни это, когда спросят»
// Делаем и проверяем
mockMvc.perform(get("/api/users/1")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()) // Ждём, что статус 200, а не 404 или 500, ёпта
.andExpect(jsonPath("$.id").value(1L)) // И что в JSON поле id равно единице
.andExpect(jsonPath("$.name").value("Alice")); // И имя Alice, а не Вася, блядь
verify(userService).findById(1L); // А тут мы, как хипстеры, проверяем, что сервис вообще вызвали, а не проёбали
}
}
2. А теперь по-взрослому, интеграционное тестирование (@SpringBootTest):
Тут поднимается ВСЁ, весь контекст, как на боевом сервере. И мы долбимся в него по-настоящему, через HTTP. Терпения ебать ноль, но надо.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) // Поднимаем приложение на случайном порту, чтобы не пересекаться
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate; // Это наш грузовик, который будет возить HTTP-запросы туда-сюда
@Test
void getUserById_Integration() {
ResponseEntity<User> response = restTemplate.getForEntity("/api/users/1", User.class); // Поехали, сука!
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); // Надеемся, что не 500 Internal Server Error
assertThat(response.getBody().getName()).isNotNull(); // И что имя у пользователя есть, а не null, блядь
}
}
Главные аннотации, без которых нихуя не получится: @WebMvcTest (когда хочешь только кусочек), @SpringBootTest (когда готов к овердохуища нагрузки), @MockBean (чтобы подсунуть Spring'у свою подставную суку вместо настоящего бина). Вот и вся магия, в рот меня чих-пых!