Тестирование в Java: unit, integration, e2e от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Зачем нужно тестирование в Java?

Каждый Java-разработчик хотя бы раз сталкивался с ситуацией, когда после изменения одной строчки кода «ломалась» вся система. Чтобы избежать подобных катастроф, индустрия выработала стройную систему тестирования. В этой статье мы разберём три уровня тестирования в Java: unit (модульное), integration (интеграционное) и e2e (сквозное). Вы узнаете, чем они отличаются, какие инструменты использовать и как правильно писать тесты на Java.

Независимо от того, пишете ли вы микросервисы на Spring Boot или десктопные приложения, понимание пирамиды тестирования — обязательный навык. Поехали!

1. Unit-тестирование: Фундамент качества

Unit-тесты (модульные тесты) проверяют работу отдельных классов или методов в изоляции от внешних зависимостей. Это самый быстрый и дешёвый уровень тестирования.

1.1 Основные инструменты

  • JUnit 5 — стандартный фреймворк для Java (последняя версия — Jupiter).
  • Mockito — библиотека для создания mock-объектов (заглушек).
  • AssertJ — библиотека с богатым набором fluent-ассертов.

1.2 Пример unit-теста с JUnit 5 и Mockito

Допустим, у нас есть сервис UserService, который зависит от репозитория UserRepository:

public class UserService {
    private final UserRepository repository;

    public UserService(UserRepository repository) {
        this.repository = repository;
    }

    public String getUserName(Long id) {
        User user = repository.findById(id);
        return user != null ? user.getName() : "Unknown";
    }
}

Напишем unit-тест, изолируя внешнюю зависимость через Mockito:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void testGetUserName_WhenUserExists() {
        // Arrange
        User mockUser = new User(1L, "Alice");
        when(userRepository.findById(1L)).thenReturn(mockUser);

        // Act
        String result = userService.getUserName(1L);

        // Assert
        assertEquals("Alice", result);
    }

    @Test
    void testGetUserName_WhenUserNotFound() {
        when(userRepository.findById(99L)).thenReturn(null);

        String result = userService.getUserName(99L);

        assertEquals("Unknown", result);
    }
}

Правило хорошего тона: один тест — одна проверка. Используйте понятные имена методов (например, testGetUserName_WhenUserExists).

2. Integration-тестирование: Проверка взаимодействий

Интеграционные тесты проверяют, как компоненты системы работают вместе: база данных, файловая система, внешние API. Они медленнее unit-тестов, но дают больше уверенности в корректности связки.

2.1 Инструменты для интеграционного тестирования Java

  • Spring Boot Test — @SpringBootTest для поднятия контекста приложения.
  • Testcontainers — запуск реальных БД (PostgreSQL, MySQL) в Docker-контейнерах.
  • H2 — in-memory база данных для быстрых тестов.

2.2 Пример интеграционного теста с Spring Boot и Testcontainers

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest
@Testcontainers
class UserRepositoryIntegrationTest {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15");

    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired
    private UserRepository userRepository;

    @Test
    void testSaveAndFindUser() {
        User user = new User(null, "Bob");
        User saved = userRepository.save(user);

        User found = userRepository.findById(saved.getId()).orElse(null);

        assertThat(found).isNotNull();
        assertThat(found.getName()).isEqualTo("Bob");
    }
}

Важно: В реальных проектах не злоупотребляйте @SpringBootTest. Для тестирования только слоя доступа используйте @DataJpaTest — это значительно быстрее.

3. E2E-тестирование: Сквозная проверка пользовательского сценария

E2E (End-to-End) тесты имитируют действия реального пользователя. Они запускают приложение целиком (фронтенд + бэкенд + БД) и проверяют критические сценарии: регистрацию, оформление заказа, логин.

3.1 Инструменты для E2E тестирования Java

  • Selenium WebDriver — классика для веб-приложений.
  • Playwright for Java — современная альтернатива с лучшей поддержкой ожиданий.
  • Cucumber — BDD-фреймворк для написания тестов на естественном языке (Gherkin).

3.2 Пример E2E теста с Selenium и JUnit

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

import static org.junit.jupiter.api.Assertions.assertTrue;

class LoginE2ETest {

    private WebDriver driver;

    @BeforeEach
    void setUp() {
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.get("https://test-site.com/login");
    }

    @Test
    void testSuccessfulLogin() {
        WebElement username                

Блоги

Рекомендаций по книгам