Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что покрывают тесты
Тесты — это автоматические проверки, которые убеждаются в том, что код работает как ожидается. Они покрывают различные аспекты: функциональность, граничные случаи, производительность, интеграцию и надёжность.
Основные типы тестов
1. Unit тесты
// Покрывают отдельные методы/функции в изоляции
public class CalculatorTest {
private Calculator calculator;
@Before
public void setUp() {
calculator = new Calculator();
}
@Test
public void testAddition() {
// Arrange
int a = 5, b = 3;
// Act
int result = calculator.add(a, b);
// Assert
assertEquals(8, result);
}
@Test
public void testDivisionByZero() {
// Покрывает граничный случай
assertThrows(ArithmeticException.class, () -> {
calculator.divide(10, 0);
});
}
}
// Покрывает:
// - Корректность бизнес-логики
// - Граничные случаи
// - Обработка ошибок
2. Integration тесты
// Покрывают взаимодействие между компонентами
@SpringBootTest
public class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@Test
public void testUserCreationAndRetrieval() {
// Покрывает: сохранение в БД + получение
User user = new User("john@example.com", "John");
User saved = userService.createUser(user);
User retrieved = userRepository.findById(saved.getId()).orElse(null);
assertNotNull(retrieved);
assertEquals("john@example.com", retrieved.getEmail());
}
@Test
public void testEmailNotification() {
// Покрывает: бизнес-логика + внешний сервис
User user = userService.createUser(new User("test@example.com", "Test"));
// Email должен быть отправлен
// Проверяется взаимодействие с EmailService
}
}
// Покрывает:
// - Интеграцию с БД
// - Интеграцию с внешними сервисами
// - Взаимодействие между слоями
3. API/Controller тесты
// Покрывают REST endpoints
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class UserControllerTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testCreateUser() {
// Покрывает: HTTP запрос → ответ
UserRequest request = new UserRequest("john@example.com", "John");
ResponseEntity<UserResponse> response = restTemplate.postForEntity(
"/api/users",
request,
UserResponse.class
);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
assertNotNull(response.getBody().getId());
}
@Test
public void testGetUser() {
// Покрывает: GET запрос
ResponseEntity<UserResponse> response = restTemplate.getForEntity(
"/api/users/1",
UserResponse.class
);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("john@example.com", response.getBody().getEmail());
}
@Test
public void testUserNotFound() {
// Покрывает: обработка 404 ошибок
ResponseEntity<String> response = restTemplate.getForEntity(
"/api/users/99999",
String.class
);
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
}
}
// Покрывает:
// - HTTP status коды
// - Валидация входных данных
// - Формат ответа (JSON)
// - Обработка ошибок
4. End-to-End (E2E) тесты
// Покрывают полный пользовательский сценарий
public class UserFlowE2ETest {
@Test
public void testCompleteUserRegistrationFlow() {
// 1. Пользователь регистрируется
// 2. Получает email с подтверждением
// 3. Подтверждает email
// 4. Логинится в систему
// 5. Создаёт профиль
// 6. Получает доступ к защищённым ресурсам
// Покрывает весь цикл жизни пользователя
}
}
// Покрывает:
// - Реальный сценарий использования
// - Все слои приложения
// - Интеграцию со всеми сервисами
5. Performance тесты
// Покрывают производительность и нагрузку
public class PerformanceTest {
@Test
public void testLargeDataProcessing() {
List<Integer> data = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
data.add(i);
}
long startTime = System.nanoTime();
int result = data.stream().filter(x -> x > 500_000).sum();
long duration = System.nanoTime() - startTime;
// Проверяем, что исполнение быстрое (< 100мс)
assertTrue(duration < 100_000_000, "Слишком медленно");
}
@Test
public void testDatabaseQueryPerformance() {
// Убеждаемся, что запрос БД выполняется < 500мс
long start = System.currentTimeMillis();
List<User> users = userRepository.findAllActive();
long duration = System.currentTimeMillis() - start;
assertTrue(duration < 500);
}
}
// Покрывает:
// - Время исполнения
// - Использование памяти
// - Масштабируемость
Граничные случаи (Edge Cases)
// Тесты также должны покрывать граничные случаи
public class EdgeCaseTests {
@Test
public void testNullInput() {
// Покрывает null значения
assertThrows(NullPointerException.class, () -> {
service.process(null);
});
}
@Test
public void testEmptyCollection() {
// Покрывает пустые коллекции
List<Integer> empty = new ArrayList<>();
int result = calculator.sum(empty);
assertEquals(0, result);
}
@Test
public void testMaxValue() {
// Покрывает максимальные значения
int result = calculator.add(Integer.MAX_VALUE, Integer.MAX_VALUE);
// может быть ошибка переполнения
}
@Test
public void testNegativeValues() {
// Покрывает отрицательные значения
int result = calculator.multiply(-5, -3);
assertEquals(15, result);
}
}
Coverage (покрытие кода)
// Coverage показывает процент кода, покрытого тестами
// Хорошие практики покрытия:
// - 90%+ для production кода
// - 100% для критичных функций
// - 70%+ минимально
// Инструменты
// - JaCoCo (Java Code Coverage)
// - Cobertura
// - Emma
// Пример: для метода
public boolean isAdult(int age) {
if (age < 0) return false; // Граничный случай
return age >= 18; // Основная логика
}
// Тесты, которые покрывают все пути:
// - isAdult(-1) -> false
// - isAdult(0) -> false
// - isAdult(17) -> false
// - isAdult(18) -> true
// - isAdult(100) -> true
Что не нужно тестировать
// Не тестируй:
// 1. Getter/Setter (если нет логики)
// 2. Конструкторы POJO (простые присваивания)
// 3. Библиотечный код (предполагаем, что работает)
// 4. Конфигурационные классы
// Тестируй:
// 1. Бизнес-логика
// 2. Граничные случаи
// 3. Интеграции
// 4. Обработка ошибок
// 5. Критичные пути
Пирамида тестов
E2E (10%)
/ \
Integration (20%)
/ \
Unit (70%)
Заключение
Тесты покрывают:
- Функциональность (работает ли код как задумано)
- Граничные случаи (null, пустые значения, максимумы)
- Интеграцию (взаимодействие компонентов)
- Производительность (быстро ли работает)
- Надёжность (обрабатывает ли ошибки)
- Регрессию (не сломалось ли уже работающее)
Хорошее тестирование — это инвестиция, которая окупается через повышение надёжности, упрощение рефакторинга и снижение багов в production.