← Назад к вопросам

На чем строится пирамида тестирования

2.0 Middle🔥 181 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пирамида тестирования

Пирамида тестирования — это концепция, которая описывает оптимальное распределение различных типов тестов в проекте. Идея заключается в том, что нужно иметь много быстрых unit-тестов, меньше интеграционных тестов и совсем немного медленных E2E тестов. Это обеспечивает баланс между полнотой покрытия и скоростью обратной связи при разработке.

Структура пирамиды (снизу вверх)

1. Unit-тесты (база пирамиды)

  • Количество: максимальное (50-60% всех тестов)
  • Скорость: очень быстрые (миллисекунды)
  • Масштаб: тестируют отдельные методы и классы
  • Изоляция: полная изоляция от внешних зависимостей (БД, API)
  • Инструменты: JUnit, Mockito, Testng

Unit-тесты проверяют логику отдельных компонентов в изоляции:

// Тест для бизнес-логики
public class CalculatorTest {
    
    @Test
    public void testAddition() {
        Calculator calc = new Calculator();
        int result = calc.add(2, 3);
        assertEquals(5, result);
    }
    
    @Test
    public void testDivisionByZero() {
        Calculator calc = new Calculator();
        assertThrows(IllegalArgumentException.class, () -> calc.divide(10, 0));
    }
}

2. Интеграционные тесты (середина пирамиды)

  • Количество: среднее (20-30% всех тестов)
  • Скорость: медленнее, чем unit-тесты (секунды)
  • Масштаб: тестируют взаимодействие нескольких компонентов
  • Изоляция: могут использовать реальную БД, API, сообщения очередей
  • Инструменты: TestContainers, @DataJpaTest, @WebMvcTest

Интеграционные тесты проверяют, как компоненты работают вместе:

// Интеграционный тест с БД
@DataJpaTest
public class UserRepositoryIntegrationTest {
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    public void testFindUserByEmail() {
        User user = new User("test@example.com", "John");
        userRepository.save(user);
        
        User found = userRepository.findByEmail("test@example.com");
        assertNotNull(found);
        assertEquals("John", found.getName());
    }
}

3. E2E тесты (вершина пирамиды)

  • Количество: минимальное (10-15% всех тестов)
  • Скорость: медленные (десятки секунд или минуты)
  • Масштаб: тестируют полный пользовательский сценарий
  • Изоляция: нет изоляции, используется полная система
  • Инструменты: Selenium, Playwright, Cypress, TestNG

E2E тесты проверяют, что приложение работает корректно с точки зрения пользователя:

// E2E тест UI с Selenium
public class LoginE2ETest {
    
    private WebDriver driver;
    
    @Before
    public void setUp() {
        driver = new ChromeDriver();
        driver.get("http://localhost:8080/login");
    }
    
    @Test
    public void testSuccessfulLogin() {
        WebElement emailInput = driver.findElement(By.id("email"));
        emailInput.sendKeys("user@example.com");
        
        WebElement passwordInput = driver.findElement(By.id("password"));
        passwordInput.sendKeys("password123");
        
        WebElement loginButton = driver.findElement(By.id("loginBtn"));
        loginButton.click();
        
        WebElement dashboard = driver.findElement(By.id("dashboard"));
        assertTrue(dashboard.isDisplayed());
    }
    
    @After
    public void tearDown() {
        driver.quit();
    }
}

Практическая реализация

// Service с бизнес-логикой
public class PaymentService {
    private PaymentRepository paymentRepository;
    private NotificationService notificationService;
    
    public PaymentService(PaymentRepository repo, NotificationService notify) {
        this.paymentRepository = repo;
        this.notificationService = notify;
    }
    
    public Payment processPayment(long orderId, BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Amount must be positive");
        }
        
        Payment payment = new Payment(orderId, amount);
        paymentRepository.save(payment);
        notificationService.notifySuccess(orderId);
        return payment;
    }
}

// Unit-тест (мокируем зависимости)
@RunWith(MockitoJUnitRunner.class)
public class PaymentServiceUnitTest {
    
    @Mock
    private PaymentRepository paymentRepository;
    
    @Mock
    private NotificationService notificationService;
    
    @InjectMocks
    private PaymentService paymentService;
    
    @Test
    public void testProcessPaymentSuccess() {
        BigDecimal amount = new BigDecimal("100.00");
        Payment expectedPayment = new Payment(1L, amount);
        
        when(paymentRepository.save(any())).thenReturn(expectedPayment);
        
        Payment result = paymentService.processPayment(1L, amount);
        
        assertNotNull(result);
        assertEquals(amount, result.getAmount());
        verify(notificationService).notifySuccess(1L);
    }
    
    @Test
    public void testProcessPaymentInvalidAmount() {
        assertThrows(IllegalArgumentException.class, 
            () -> paymentService.processPayment(1L, BigDecimal.ZERO));
    }
}

Рекомендуемое распределение

  • Unit-тесты: 70-75%
  • Интеграционные тесты: 15-20%
  • E2E тесты: 5-10%

Это распределение обеспечивает быстрый feedback при разработке (unit-тесты запускаются за секунды) и уверенность в правильности работы системы (E2E тесты проверяют реальные сценарии).

Преимущества пирамиды тестирования

  • Скорость обратной связи: unit-тесты дают результат почти мгновенно
  • Стабильность: fewer flaky tests благодаря минимизации E2E тестов
  • Экономия ресурсов: unit-тесты требуют мало вычислительных ресурсов
  • Локализация ошибок: unit-тесты помогают быстро найти причину проблемы
  • Уверенность в коде: E2E тесты подтверждают, что система работает в целом
На чем строится пирамида тестирования | PrepBro