Пирамида тестов
Здоровая стратегия — пирамида: много быстрых unit-тестов в основании, меньше интеграционных (срезы и Testcontainers) посередине и совсем немного сквозных (end-to-end) сверху.
Причина — скорость и стабильность: unit-тесты исполняются за миллисекунды и почти не «флакуют», а тяжёлые сквозные тесты медленны и хрупки. Антипаттерн «перевёрнутая пирамида» (всё через @SpringBootTest) делает сборку медленной и ненадёжной.
Unit без Spring
Чистую бизнес-логику тестируют обычным JUnit + Mockito, БЕЗ поднятия Spring-контекста: создают объект через new, передают моки зависимостей. Это самые быстрые и многочисленные тесты.
Возможность так тестировать — прямое следствие конструкторной инъекции (см. урок про IoC): класс собирается без контейнера. Field injection эту возможность ломает.
Slice-тесты
Когда нужен Spring, но не весь, используют срезы — они поднимают только часть контекста и потому быстры. @WebMvcTest — только web-слой (контроллеры + MockMvc), сервисы подменяют @MockBean. @DataJpaTest — только JPA-слой с БД (встроенной или Testcontainers), каждый тест по умолчанию в транзакции с откатом. Есть и @JsonTest, @RestClientTest и др.
Срез грузит ровно нужные бины (например, @WebMvcTest не создаёт сервисы и репозитории), что и даёт выигрыш по скорости против полного контекста.
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired MockMvc mvc;
@MockBean UserService service; // зависимость контроллера — мок
}
@SpringBootTest и моки
@SpringBootTest поднимает весь (или большой) контекст для сквозных сценариев. webEnvironment задаёт режим: MOCK (без сервера, с MockMvc) или RANDOM_PORT (реальный встроенный сервер + TestRestTemplate/WebTestClient). Это самые дорогие тесты — их держат точечно.
@MockBean (с Spring Boot 3.4 — @MockitoBean, старая аннотация помечена устаревшей) заменяет бин в контексте моком (например, внешний клиент), но важно: добавление @MockBean меняет контекст и ломает его кэширование между тестами (каждая уникальная конфигурация контекста поднимается заново) — это частая причина медленных тест-сьютов. MockMvc гоняет MVC без реального сокета; WebTestClient — для WebFlux и реального порта.
Testcontainers
Testcontainers запускает РЕАЛЬНУЮ инфраструктуру в Docker-контейнерах (PostgreSQL, Kafka, Redis) на время теста. Это убирает расхождение с production по SQL-диалекту, драйверу и поведению брокера, которое дают H2/embedded-заглушки.
С Spring Boot 3.1 связка упростилась: @ServiceConnection автоматически прописывает контейнер как источник данных/брокер в контекст — не нужно вручную пробрасывать url/credentials. Такие тесты дороже unit, поэтому их держат фокусными: миграции, репозитории, транзакции, wiring продюсеров/консьюмеров.
@Testcontainers @DataJpaTest
class RepoTest {
@Container @ServiceConnection
static PostgreSQLContainer<?> db = new PostgreSQLContainer<>("postgres:16");
}
Контрактные тесты
Контрактные тесты проверяют ДОГОВОР между сервисами: HTTP-схема, статус-коды, обязательные поля, схема сообщений и совместимость событий. Инструменты — Spring Cloud Contract, Pact.
Они особенно ценны, когда команды развивают producer и consumer независимо: контракт ловит несовместимое изменение (удалили поле, сменили тип) ДО интеграции и продакшена, не поднимая оба сервиса вместе.
Как отвечать на собеседовании
Объясните пирамиду (много unit без Spring → срезы/Testcontainers → мало e2e) и почему перевёрнутая пирамида плоха. Свяжите unit без контекста с конструкторной инъекцией. Различите @WebMvcTest/@DataJpaTest (срезы, быстро) и @SpringBootTest (весь контекст, дорого) и предупредите про @MockBean, ломающий кэш контекста. Подчеркните Testcontainers (реальная БД/брокер вместо H2, @ServiceConnection) и контрактные тесты для независимых команд.