Тестирование и Spring Boot Actuator
Код без тестов — мина замедленного действия. Spring Boot даёт срезы для быстрых тестов, а Actuator показывает здоровье приложения в проде.
Суть: юнит-тесты проверяют логику с Mockito без Spring. Срезы (@WebMvcTest, @DataJpaTest) поднимают часть контекста. @SpringBootTest — полный интеграционный тест. Actuator открывает health и метрики.
Тесты — это не бюрократия, а страховка от регрессий. Меняя код, вы хотите быть уверены, что не сломали старое. Spring Boot делает тестирование быстрым за счёт «срезов» — поднятия только нужной части приложения.
Юнит-тест с Mockito
Благодаря конструкторному внедрению сервис можно создать обычным new, подсунув ему моки зависимостей:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock UserRepository repo;
@InjectMocks UserService service;
@Test
void returnsUserWhenExists() {
when(repo.findById(7L))
.thenReturn(Optional.of(new User(7L, "Анна")));
var result = service.findById(7L);
assertEquals("Анна", result.name());
verify(repo).findById(7L);
}
}
Здесь Spring вообще не поднимается — тест быстрый. Это и есть награда за конструкторное внедрение из раздела про DI.
Срезы и интеграционные тесты
| Аннотация | Что поднимает |
|---|---|
| @WebMvcTest | Только веб-слой (контроллеры, без БД) |
| @DataJpaTest | Только слой данных (репозитории + тестовая БД) |
| @SpringBootTest | Весь контекст — полный интеграционный тест |
Spring Boot Actuator
Actuator — это набор готовых эндпоинтов для эксплуатации: /actuator/health (живо ли приложение), /actuator/metrics (метрики), /actuator/info. Их используют системы мониторинга и оркестраторы (Kubernetes) для проверки готовности.
management:
endpoints:
web:
exposure:
include: health, info, metrics
endpoint:
health:
show-details: when-authorized
Как работает под капотом
Пирамида тестов и Actuator
┌──────────────────────────────────┐
│ @SpringBootTest (мало, медленно) │ весь контекст
├──────────────────────────────────┤
│ @WebMvcTest / @DataJpaTest │ срез слоя
├──────────────────────────────────┤
│ юнит-тесты + Mockito (много) │ без Spring
└──────────────────────────────────┘
Actuator в проде:
Kubernetes --GET /actuator/health--> приложение
<-- {"status":"UP"} -- жив, шлём трафик
Смоделируем мок-зависимость и health-проверку:
# Мок репозитория + health-check, как Mockito и Actuator
class MockRepo:
def __init__(self, data):
self.data = data
self.calls = []
def find_by_id(self, id):
self.calls.append(id) # verify(repo).findById(...)
return self.data.get(id)
def service_find(repo, id):
user = repo.find_by_id(id)
if user is None:
raise ValueError("Не найден")
return user
repo = MockRepo({7: {"id": 7, "name": "Анна"}})
print("Тест:", service_find(repo, 7))
print("Репозиторий вызван с:", repo.calls) # [7]
def health_check(db_ok, disk_ok):
status = "UP" if db_ok and disk_ok else "DOWN"
return {"status": status, "components": {"db": db_ok, "disk": disk_ok}}
print("Health:", health_check(True, True))
print("Health:", health_check(False, True))
Нажмите «Попробуй сам ▶»: мок фиксирует вызовы (как verify), а health-check агрегирует состояние подсистем — как Actuator.
Частые ошибки
- Только @SpringBootTest везде. Полный контекст медленный; для слоя берите срез.
- Открыть все эндпоинты Actuator наружу. Часть из них чувствительна — ограничивайте доступ.
- Тесты, зависящие от порядка. Каждый тест должен быть независимым и воспроизводимым.
Best practices
- Стройте пирамиду: много юнит-тестов, меньше срезов, единичные
@SpringBootTest. - Используйте конструкторное внедрение — оно делает юнит-тесты тривиальными.
- Включайте Actuator
healthдля проб готовности, но защищайте чувствительные эндпоинты.
Итог: тестируйте пирамидой — юнит-тесты с Mockito, срезы для слоёв, интеграционные для целого. Actuator даёт готовые health и метрики для эксплуатации в проде.