Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Unit-тестирование и понятие Unit
Unit (модуль) в unit-тестировании — это **наименьшая тестируемая часть приложения, которая может быть протестирована изолированно**. Обычно это одна функция, метод класса или небольшой компонент.
Что такое Unit?
Unit — это отдельная, логически завершённая часть кода, которая:
- Имеет чёткую ответственность: выполняет одну задачу
- Может быть протестирована независимо: без зависимостей от других модулей
- Имеет входные данные (input): параметры метода
- Имеет выходные данные (output): возвращаемое значение
Примеры Unit
// Unit 1: Вычисление скидки
public class DiscountCalculator {
public double calculateDiscount(double originalPrice, int discountPercent) {
// Один Unit — один метод
return originalPrice * (1 - discountPercent / 100.0);
}
}
// Unit 2: Валидация email
public class EmailValidator {
public boolean isValidEmail(String email) {
// Один Unit — проверка email
return email != null && email.contains("@") && email.contains(".");
}
}
// Unit 3: Поиск максимального значения
public class ArrayUtils {
public int findMax(int[] arr) {
// Один Unit — поиск максимума
if (arr == null || arr.length == 0) {
throw new IllegalArgumentException("Array is empty");
}
return java.util.Arrays.stream(arr).max().orElse(Integer.MIN_VALUE);
}
}
Unit vs Integration тестирование
| Характеристика | Unit | Integration |
|---|---|---|
| Область тестирования | Один метод/компонент | Несколько компонентов вместе |
| Скорость выполнения | Очень быстро (мс) | Медленнее (сек) |
| Зависимости | Мокируются | Используются реальные |
| Сложность | Простое | Сложнее |
| Частота запуска | Часто (CI/CD) | Реже |
| Что тестирует | Логику | Интеграцию компонентов |
Unit-тестирование с JUnit
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class DiscountCalculatorTest {
private DiscountCalculator calculator = new DiscountCalculator();
@Test
public void testCalculateDiscount_AppliesDiscount() {
// Arrange (подготовка)
double originalPrice = 100.0;
int discountPercent = 20;
// Act (выполнение)
double result = calculator.calculateDiscount(originalPrice, discountPercent);
// Assert (проверка)
assertEquals(80.0, result);
}
@Test
public void testCalculateDiscount_NoDiscount() {
double result = calculator.calculateDiscount(100.0, 0);
assertEquals(100.0, result);
}
@Test
public void testCalculateDiscount_FullDiscount() {
double result = calculator.calculateDiscount(100.0, 100);
assertEquals(0.0, result);
}
}
AAA паттерн (Arrange-Act-Assert)
Структура unit-теста:
@Test
public void testUserCreation() {
// ARRANGE — подготовка данных и объектов
String username = "john_doe";
String email = "john@example.com";
User user = new User();
// ACT — выполнение тестируемого действия
user.setUsername(username);
user.setEmail(email);
// ASSERT — проверка результатов
assertEquals(username, user.getUsername());
assertEquals(email, user.getEmail());
assertNotNull(user);
}
Мокирование зависимостей
Unit — это изолированный модуль. Зависимости мокируются:
import org.mockito.Mock;
import org.mockito.InjectMocks;
import static org.mockito.Mockito.*;
public class UserServiceTest {
@Mock
private UserRepository userRepository; // Мокируем зависимость
@InjectMocks
private UserService userService; // Инжектим в сервис
@Test
public void testGetUserById() {
// Arrange
User expectedUser = new User(1L, "John Doe");
when(userRepository.findById(1L)).thenReturn(expectedUser);
// Act
User result = userService.getUserById(1L);
// Assert
assertEquals("John Doe", result.getName());
verify(userRepository, times(1)).findById(1L);
}
}
Шаги для написания Unit-теста
1. Определи Unit (что тестировать):
public class PaymentProcessor {
public boolean processPayment(double amount) {
// Unit — обработка платежа
return amount > 0;
}
}
2. Напиши тест:
public class PaymentProcessorTest {
private PaymentProcessor processor = new PaymentProcessor();
@Test
public void testProcessPayment_PositiveAmount_ReturnsTrue() {
boolean result = processor.processPayment(100.0);
assertTrue(result);
}
@Test
public void testProcessPayment_NegativeAmount_ReturnsFalse() {
boolean result = processor.processPayment(-50.0);
assertFalse(result);
}
@Test
public void testProcessPayment_ZeroAmount_ReturnsFalse() {
boolean result = processor.processPayment(0.0);
assertFalse(result);
}
}
Хорошие Unit-тесты имеют свойства FIRST
F — Fast (быстрые): Выполняются за миллисекунды
// Быстро — вычисление в памяти
@Test
public void quickTest() {
assertEquals(4, 2 + 2);
}
I — Independent (независимые): Не зависят друг от друга
// Каждый тест может запуститься отдельно
@Test
public void test1() { /* ... */ }
@Test
public void test2() { /* ... */ } // Не зависит от test1
R — Repeatable (повторяемые): Дают одинаковый результат каждый раз
// Одинаковый результат при множественных запусках
@Test
public void repeatableTest() {
assertEquals(5, calculator.add(2, 3));
}
E — Explicit (явные): Ясно показывают, что тестируют
// Название явно описывает тест
@Test
public void testAddition_WithPositiveNumbers_ReturnsSum() {
assertEquals(5, calculator.add(2, 3));
}
T — Timely (своевременные): Пишутся перед кодом (TDD) или с кодом
// Пишем тест в момент разработки
Примеры различных Unit-тестов
Тест исключений:
@Test
public void testDivisionByZero_ThrowsException() {
assertThrows(ArithmeticException.class, () -> {
calculator.divide(10, 0);
});
}
Тест коллекций:
@Test
public void testAddToList_SizeIncreases() {
List<String> list = new ArrayList<>();
list.add("item");
assertEquals(1, list.size());
assertTrue(list.contains("item"));
}
Тест временных интервалов:
@Test
public void testOperationTimeout() {
assertTimeout(java.time.Duration.ofSeconds(2), () -> {
// Операция должна завершиться менее чем за 2 секунды
complexOperation();
});
}
Процентное содержание тестов
Обычное распределение:
- 70-80% Unit тесты — быстрые, дешёвые, много
- 10-20% Integration тесты — медленнее, дороже
- 5-10% E2E тесты — самые медленные, самые дорогие
Заключение
Unit-тестирование — это фундамент качественного software. Unit — это минимальная, изолированная, логически завершённая часть кода, которая тестируется отдельно от остального приложения. Правильное unit-тестирование гарантирует стабильность и надёжность приложения.