Гид по технологиям

Вложенные тесты в JUnit 5: как и зачем

3 min read Тестирование Обновлено 29 Mar 2026
Вложенные тесты в JUnit 5: как и зачем
Вложенные тесты в JUnit 5: как и зачем

Три плоских камня в стопке: самый маленький сверху, самый большой снизу.

Что такое вложенный тест?

Аннотация @Nested в JUnit 5 помечает внутренний класс как часть внешнего тестового класса. Вложенный тест — это класс с @Nested внутри верхнего тестового класса. Такой класс наследует окружение и поля родителя, что упрощает повторное использование ресурсов.

Краткое определение: вложенный тест — внутренний тестовый класс, логически группирующий связанные сценарии.

Когда стоит создавать вложенные тесты

Вложенный тест подходит, если:

  • есть логическая группа тестов (например, различные состояния объекта);
  • один метод выполняет несколько ролей и для каждой нужен отдельный набор проверок;
  • нужно разделять конфигурацию и предусловия для разных групп тестов.

Важно: не злоупотребляйте вложенностью. Если уровень вложенности становится глубоким, код теста сложнее читать и поддерживать.

Создание Java-класса для тестирования

Ниже — пример класса Customer из торгового приложения, который мы будем тестировать. Сохраните код как есть в проекте.

publicclassCustomer{  
protectedint customerId;  
protected String customerName;  
protected String customerCode;  

// default constructor  
publicCustomer(){  
this.customerId = 0;  
this.customerName = "";  
this.customerCode ="";  
}  

// primary constructor  
publicCustomer(int customerId, String customerName, String customerCode){  
this.customerId = customerId;  
this.customerName = customerName;  
this.customerCode = customerCode;  
}  

// copy constructor  
publicCustomer(Customer customer){  
this.customerId = customer.customerId;  
this.customerName = customer.customerName;  
this.customerCode = customer.customerCode;  
}  

// getters and setters  
publicintgetCustomerId(){  
return customerId;  
}  

publicvoidsetCustomerId(int customerId){  
this.customerId = customerId;  
}  

public String getCustomerName(){  
return customerName;  
}  

publicvoidsetCustomerName(String customerName){  
this.customerName = customerName;  
}  

public String getCustomerCode(){  
return customerCode;  
}  

publicvoidsetCustomerCode(String customerCode){  
this.customerCode = customerCode;  
}  

// determine a customer discount percentage based on customer type  
publicdoublecustomerType(String customerCode){  
double discount = 0;  

if (customerCode.toLowerCase().equals("pre")) {  
discount = 0.10;  
} elseif (customerCode.toLowerCase().equals("gen")) {  
discount = 0.02;  
} elseif (customerCode.toLowerCase().equals("new")) {  
discount = 0.05;    
}  

return discount;                                   
}  

// determine a customer's grandTotal based on customer type  
publicdoublegrandTotal(double total){  
double discount = customerType(customerCode);  
double discountPercentage = total * discount;  
double finalTotal = total - discountPercentage;  
return finalTotal;  
}  
}  

Этот класс содержит конструкторы, геттеры/сеттеры и два метода, которые мы будем проверять.

Создание вложенного теста в JUnit 5

Ниже — тестовый класс с вложенным классом, который использует @Nested и @DisplayName. Скопируйте код в тесты проекта.

importstaticorg.junit.jupiter.api.Assertions.*;  

importorg.junit.jupiter.api.DisplayName;  
importorg.junit.jupiter.api.Nested;  
importorg.junit.jupiter.api.Test;  

@DisplayName("Customer Test Class Showing How to Create Nested Tests.")  
classCustomerTest{  
protectedint customerId = 301;  
protected String customerName = "Mike Wilson";  
protected String customerCode = "Pre";  
protecteddouble total = 600;  

@Nested  
@DisplayName("Customer Builder Nested Test Class Within a Top-Level Test Class")  
classCustomerBuilderTest{  
Customer customer = new Customer(customerId, customerName, customerCode);          
double grandTotal = customer.grandTotal(total);  

@Test  
@DisplayName("Testing the Customer's Class Constructors, Getters and Setters, and Methods.")  
voidcustomerBuilder(){                                                                    
assertAll(() -> {  
assertEquals(customerId, customer.getCustomerId());  
assertEquals(customerName, customer.getCustomerName());  
assertEquals(customerCode, customer.getCustomerCode());  
assertEquals(0.10, customer.customerType(customerCode));  
assertEquals(540, grandTotal);  
});  
}  
}  
}

Вложенный класс CustomerBuilderTest создаёт объект Customer и выполняет набор assertions. В результате отчёт тестирования хранит структуру в виде иерархии тестовых классов.

Отчёт о выполнении вложенных тестов

Почему важно уметь тестировать ПО

Технологии повсеместны. Ошибка в коде может иметь серьёзные последствия. Чем выше риск, тем строже должны быть тесты. Важность тестирования проявляется на всех стадиях разработки: от юнит-тестов до системных испытаний.

Когда вложенные тесты не подходят

  • Если конструкторы или поля создают боковые эффекты, совместное использование окружения может скрыть ошибки.
  • Когда тесты разрастаются по количеству — глубокая вложенность снижает читабельность.
  • Для простых изолированных тестов вложенность добавляет лишний общий контекст.

Альтернативные подходы

  • Вынесение общих настроек в @BeforeEach / @BeforeAll.
  • Использование параметризованных тестов @ParameterizedTest для проверок с набором данных.
  • Создание отдельных классов тестов по функциональным зонам.

Ментальные модели и эвристики

  • Модель “контекст → проверка”: каждый вложенный класс описывает контекст, а тесты — ожидаемое поведение.
  • Правило двух уровней: не более двух вложенных уровней для ясности.
  • Если требуется переиспользовать состояние — вынесите его в родительский класс.

Чек-листы по ролям

Разработчик:

  • Разбить сценарии по состояниям объекта.
  • Использовать @Nested для групп контекстов.
  • Следить за читаемостью и количеством ассертов.

QA-инженер:

  • Проверить отчёты тестов на структуру.
  • Обеспечить покрытие кейсов для каждого контекста.
  • Предложить параметры для параметризованных тестов.

Технический лидер:

  • Утвердить правила вложенности.
  • Следить за временем выполнения тестов.
  • Решать, когда рефакторить тестовую иерархию.

Мини-методология: как внедрить вложенные тесты

  1. Найдите методы с несколькими состояниями.
  2. Создайте родительский тестовый класс с общими полями.
  3. Для каждого состояния создайте @Nested класс с набором тестов.
  4. Используйте @DisplayName для понятных отчётов.
  5. Ограничьте глубину вложенности.

Критерии приёмки

  • Тесты выполняются стабильно в CI.
  • Структура отчётов отражает контексты.
  • Нет дублирования кода, ресурсы переиспользуются.
  • Время выполнения не превышает допустимого порога (по проектным правилам).

Глоссарий

  • Вложенный тест — внутренний класс с аннотацией @Nested.
  • Контекст — набор предусловий для группы тестов.
  • Ассерты — утверждения результата в тесте.

Итоги Вложенные тесты в JUnit 5 делают структуру тестов ясной и помогают повторно использовать окружение. Они удобны для тестирования методов с несколькими состояниями, но требуют осторожности: не допускать чрезмерной глубины и побочных эффектов.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как защитить телефон от слежки и перехвата
Безопасность

Как защитить телефон от слежки и перехвата

Тема и шрифт Блокнота в Windows 11
Windows

Тема и шрифт Блокнота в Windows 11

Microsoft Defender: как анализировать и удалять угрозы
Безопасность Windows

Microsoft Defender: как анализировать и удалять угрозы

Adobe Animate: руководство для начинающих
Анимация

Adobe Animate: руководство для начинающих

Mission DALEK: как создать свой эпизод Doctor Who
Развлечения

Mission DALEK: как создать свой эпизод Doctor Who

Обновление приложений в Windows 11 — руководство
Windows

Обновление приложений в Windows 11 — руководство