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

Пирамида тестирования — визуальная модель, описывающая оптимальное соотношение видов тестов: много быстрых unit-тестов в основании, меньше integration и совсем мало медленных E2E на вершине.

Зачем нужно

Без модели команды либо пишут только E2E (медленно, хрупко, дорого), либо только unit (быстро, но не проверяют интеграцию). Пирамида задаёт стратегию: вложи бюджет тестирования туда, где максимальная отдача при минимальных затратах.

Где используется

  • Планирование тестовой стратегии нового проекта
  • Аудит существующего тест-сьюта (перевёрнутая пирамида — anti-pattern)
  • Обсуждение соотношения тестов в команде

Основной контент

Классическая пирамида (Mike Cohn)

          /─────────\
         /   E2E      \     ← мало, медленные, дорогие
        /─────────────\
       / Integration   \    ← средне, реальные зависимости
      /─────────────────\
     /    Unit Tests     \  ← много, быстрые, изолированные
    /─────────────────────\

Характеристики каждого уровня

Уровень Кол-во Скорость Цена поддержки Что проверяет
Unit 70% Миллисекунды Низкая Логика функций
Integration 20% Секунды Средняя Взаимодействие слоёв
E2E 10% Минуты Высокая Пользовательские сценарии

Примеры для каждого уровня

// Unit — изолированная функция
test('calculateTotal прибавляет tax', () => {
  expect(calculateTotal({ price: 100, taxRate: 0.2 })).toBe(120);
});

// Integration — сервис + репозиторий + БД (SQLite in-memory)
test('UserService.create сохраняет пользователя в БД', async () => {
  const user = await userService.create({ name: 'Alice', email: 'alice@test.com' });
  const found = await db('users').where({ id: user.id }).first;
  expect(found.name).toBe('Alice');
});

// E2E — полный сценарий через браузер
test('пользователь регистрируется и видит dashboard', async ({ page }) => {
  await page.goto('/register');
  await page.fill('[data-testid="email"]', 'alice@test.com');
  await page.fill('[data-testid="password"]', 'Pass123!');
  await page.click('[data-testid="submit"]');
  await expect(page).toHaveURL('/dashboard');
});

Антипаттерн: перевёрнутая пирамида (Ice Cream Cone)

    /─────────────────────\
   /       E2E             \  ← много медленных E2E
  /─────────────────────────\
 / Integration               \
/─────────────────────────────\
            Unit               ← мало unit

Симптомы: CI работает 40 минут, тесты регулярно flaky, разработчики боятся запускать тесты.

Модификации пирамиды

  • Testing Trophy (Kent C. Dodds) — акцент на integration тесты для фронтенда: они дают больший ROI чем чистые unit при тестировании компонентов
  • Honeycomb (Spotify) — для микросервисов: меньше E2E, больше service-integration

Частые ошибки

  • Копирование unit-логики в E2E — E2E тест на валидацию каждого поля формы — это перевёрнутая пирамида; покрывай детали unit-тестами
  • Нет integration тестов — пропуск среднего слоя значит что баги на стыке сервисов ловятся только в E2E или production
  • Жёсткое следование 70/20/10 — это ориентир, а не закон; для конкретного проекта соотношение может быть другим

Связанные темы

Ресурсы