Spring BootMiddleTechnical
Какова роль @SpringBootTest в интеграционном тестировании?
@SpringBootTest поднимает полный Spring ApplicationContext для интеграционных тестов. Поддерживает режимы MOCK (MockMvc), RANDOM_PORT (реальный HTTP) и NONE (только контекст без веб-слоя).
@SpringBootTest в интеграционном тестировании
@SpringBootTest — аннотация Spring Test, которая поднимает полный (или частичный) контекст Spring ApplicationContext для интеграционных тестов. В отличие от юнит-тестов с @ExtendWith(MockitoExtension.class), здесь участвуют реальная автоконфигурация, бины, база данных и HTTP-слой.
Режимы webEnvironment
MOCK(по умолчанию) — создаёт mock-среду веб-контейнера, используется сMockMvc.RANDOM_PORT— запускает реальный встроенный сервер на случайном порту; используется сTestRestTemplateилиWebTestClient.DEFINED_PORT— реальный сервер на порту изapplication.properties.NONE— без веб-среды, только ApplicationContext.
Пример: тест с MockMvc
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setUp() {
userRepository.deleteAll();
userRepository.save(new User("Alice", "alice@example.com"));
}
@Test
void shouldReturnUserList() throws Exception {
mockMvc.perform(get("/api/users")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name").value("Alice"));
}
@Test
void shouldCreateUser() throws Exception {
String requestBody = """
{"name": "Bob", "email": "bob@example.com"}
""";
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value("Bob"));
}
}
Пример: тест с реальным HTTP (RANDOM_PORT)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
class OrderApiIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@LocalServerPort
private int port;
@Test
void shouldReturnOrderById() {
ResponseEntity<OrderDto> response = restTemplate
.getForEntity("/api/orders/1", OrderDto.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isNotNull();
}
}
Изоляция через @Transactional и @Sql
@SpringBootTest
@Transactional // откатывает каждый тест
@Sql("/sql/test-data.sql") // вставляет данные перед тестом
class ProductServiceIntegrationTest {
@Autowired
private ProductService productService;
@Test
void shouldFindProductByCategory() {
List<Product> products = productService.findByCategory("electronics");
assertThat(products).hasSize(3);
}
}
Мокирование отдельных бинов
@SpringBootTest
class PaymentIntegrationTest {
@MockBean // заменяет реальный бин в контексте Spring моком Mockito
private PaymentGateway paymentGateway;
@Autowired
private OrderService orderService;
@Test
void shouldProcessPayment() {
when(paymentGateway.charge(any())).thenReturn(PaymentResult.success("txn-123"));
OrderResult result = orderService.placeOrder(new OrderRequest(...));
assertThat(result.isPaid()).isTrue();
verify(paymentGateway).charge(any());
}
}
Кеширование контекста
Spring Test кеширует ApplicationContext между тестовыми классами с одинаковой конфигурацией. Использование @MockBean или @DirtiesContext создаёт новый контекст, что замедляет тесты. Группируйте тесты с одинаковым набором моков.
Подводные камни
@SpringBootTestподнимает весь контекст — тесты становятся медленными. Для тестирования одного слоя используйте слайсы:@WebMvcTest,@DataJpaTest,@JsonTest.@MockBeanинвалидирует кеш контекста — каждый класс с уникальным набором@MockBeanсоздаёт новый контекст. Сведите число комбинаций к минимуму.- Использование
RANDOM_PORTс@Transactionalне откатывает транзакции — HTTP-запросы идут через реальный контейнер в другом потоке. - Без
@ActiveProfiles("test")тест может подключиться к production-базе, еслиspring.profiles.activeне задан явно. - Не чистить БД между тестами — состояние из одного теста ломает другой. Используйте
@Transactional,@Sqlили явный@BeforeEach. @DirtiesContextна каждом тестовом классе сбрасывает кеш и многократно поднимает контекст — тестовый прогон превращается в многоминутный.- Забыть добавить
spring-boot-starter-testв зависимости — тест не скомпилируется без JUnit 5 и Spring Test.
Common mistakes
- Путать термин «springboottest» с соседним механизмом Spring Boot.
- Не называть границу lifecycle, transaction, thread или request для «springboottest».
- Игнорировать production-эффекты «springboottest»: latency, SQL shape, memory, security или observability.
What the interviewer is testing
- Попросить объяснить механизм «springboottest» на минимальном примере.
- Проверить, видит ли кандидат failure mode и диагностику для «springboottest».
- Уточнить, какие настройки или API меняют «springboottest» в реальном сервисе.