junior
Что такое Nested тесты в JUnit 5?
@Nested — аннотация JUnit 5, позволяющая создавать вложенные тестовые классы для логической группировки тестов. Это улучшает структуру и читаемость, особенно когда один класс содержит много тестов для разных сценариев.
Полный пример с Nested тестами
@DisplayName("Тесты UserService")
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
@Nested
@DisplayName("Метод findById")
class FindById {
@Test
@DisplayName("должен вернуть пользователя по существующему id")
void shouldReturnUserWhenExists() {
User user = new User(1L, "Иван");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
User result = userService.findById(1L);
assertEquals("Иван", result.getName());
}
@Test
@DisplayName("должен бросить исключение при несуществующем id")
void shouldThrowWhenNotFound() {
when(userRepository.findById(999L)).thenReturn(Optional.empty());
assertThrows(UserNotFoundException.class,
() -> userService.findById(999L));
}
}
@Nested
@DisplayName("Метод create")
class Create {
@Test
@DisplayName("должен создать пользователя с валидными данными")
void shouldCreateValidUser() {
UserDto dto = new UserDto("Иван", "ivan@example.com");
when(userRepository.save(any())).thenAnswer(inv -> {
User u = inv.getArgument(0);
u.setId(1L);
return u;
});
User result = userService.create(dto);
assertNotNull(result.getId());
verify(userRepository).save(any());
}
@Test
@DisplayName("должен бросить исключение при дублировании email")
void shouldThrowOnDuplicateEmail() {
UserDto dto = new UserDto("Иван", "existing@example.com");
when(userRepository.existsByEmail("existing@example.com"))
.thenReturn(true);
assertThrows(DuplicateEmailException.class,
() -> userService.create(dto));
verify(userRepository, never()).save(any());
}
}
}
Результат в отчёте
Пример
Тесты UserService
├── Метод findById
│ ├── должен вернуть пользователя по существующему id
│ └── должен бросить исключение при несуществующем id
├── Метод create
│ ├── должен создать пользователя с валидными данными
│ └── должен бросить исключение при дублировании email
└── Метод delete
├── должен удалить существующего пользователя
└── должен бросить исключение при удалении несуществующего
Вложенные классы имеют доступ к полям и мокам внешнего класса. При этом @BeforeEach внешнего класса выполняется перед @BeforeEach вложенного.
На собеседовании: покажите, что
@Nestedиспользуется для организации тестов по тестируемым методам или сценариям. Частая ошибка — забыть, что вложенные классы не могут иметь@BeforeAll/@AfterAllбез@TestInstance(Lifecycle.PER_CLASS).