Modern QA2026Пирамида тестирования в CI
Join

Course16 CI/CD Pipelines

Foundations · Chapter 16

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

Updated Jul 2026

Структурирование этапов пайплайна на основе пирамиды тестирования

Не все тесты должны запускаться на одном этапе. Пирамида тестирования определяет не только то, какие тесты вы пишете, но и когда они запускаются в вашем пайплайне. Структурируйте пайплайн так, чтобы обеспечить быструю обратную связь сначала и дорогую валидацию позже.

                    /\
                   /  \
                  / E2E \          Минуты  | При слиянии в main
                 /--------\
                /          \
               / Integration \     Минуты  | При pull request
              /--------------\
             /                \
            /    Unit Tests    \   Секунды | При каждом push
           /--------------------\

Этап 1: При каждом push (секунды-минуты)

Это самый быстрый цикл обратной связи. Разработчики получают результаты до того, как переключат контекст с только что написанного кода.

Что запускается здесь:

  • Линтинг и статический анализ (ESLint, Pylint, Ruff)
  • Проверка типов (TypeScript tsc --noEmit, mypy)
  • Unit-тесты с отчётом о покрытии
  • Проверка форматирования (Prettier, Black)

Почему именно эти, а не другие:

  • Они быстрые (обычно менее 2 минут)
  • Не требуют внешних сервисов (базы данных, API)
  • Ловят самые распространённые ошибки (синтаксические ошибки, несоответствия типов, нарушения логики)
# Example: Fast feedback job
lint-and-unit:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
    - run: npm ci
    - run: npm run lint
    - run: npm run typecheck
    - run: npm run test:unit -- --coverage
    - uses: actions/upload-artifact@v4
      if: always()
      with:
        name: coverage
        path: coverage/lcov.info

Целевое время: менее 3 минут. Если линтинг и unit-тесты занимают больше, разработчики перестанут их дожидаться.

Этап 2: При pull request / слиянии в develop (минуты)

Этот этап запускается, когда код предлагается для интеграции. Он ловит проблемы, требующие реальной инфраструктуры — баз данных, очередей сообщений, контрактов внешних сервисов.

Что запускается здесь:

  • Интеграционные тесты на реальных базах данных и сервисах
  • Контрактные тесты API (Pact, Schemathesis)
  • Компонентные тесты (отдельные сервисы или модули, тестируемые с реальными зависимостями)
  • Сканирование безопасности (SAST-инструменты: Snyk, Semgrep)
# Example: Integration test job with database service
integration-tests:
  needs: lint-and-unit
  runs-on: ubuntu-latest
  services:
    postgres:
      image: postgres:16
      env:
        POSTGRES_DB: test_db
        POSTGRES_PASSWORD: testpass
      ports:
        - 5432:5432
      options: >-
        --health-cmd pg_isready
        --health-interval 10s
        --health-timeout 5s
        --health-retries 5
    redis:
      image: redis:7
      ports:
        - 6379:6379
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
    - run: npm ci
    - run: npm run db:migrate
      env:
        DATABASE_URL: postgres://postgres:testpass@localhost:5432/test_db
    - run: npm run test:integration
      env:
        DATABASE_URL: postgres://postgres:testpass@localhost:5432/test_db
        REDIS_URL: redis://localhost:6379

Целевое время: менее 10 минут. Именно этот этап наиболее подвержен замедлению — следите за ним внимательно.

Этап 3: При слиянии в main / перед развёртыванием (минуты-десятки минут)

Это финальная проверка перед тем, как код попадёт к пользователям. Запускайте здесь дорогие, тщательные тесты.

Что запускается здесь:

  • Полный набор браузерных тестов на нескольких браузерах
  • Визуальные регрессионные тесты (визуальные сравнения Playwright, Percy, Chromatic)
  • Дымовые тесты производительности (Lighthouse, k6 с базовыми порогами)
  • Аудиты доступности (axe-core, Pa11y)
# Example: Cross-browser E2E tests with sharding
browser-tests:
  needs: integration-tests
  runs-on: ubuntu-latest
  strategy:
    fail-fast: false
    matrix:
      browser: [chromium, firefox, webkit]
      shard: [1, 2, 3, 4]
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
    - run: npm ci
    - uses: actions/cache@v4
      with:
        path: ~/.cache/ms-playwright
        key: playwright-${{ hashFiles('package-lock.json') }}
    - run: npx playwright install --with-deps ${{ matrix.browser }}
    - run: npx playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}/4
    - uses: actions/upload-artifact@v4
      if: failure()
      with:
        name: traces-${{ matrix.browser }}-${{ matrix.shard }}
        path: test-results/

Целевое время: менее 20 минут с параллелизацией. Без шардирования браузерные тесты легко занимают 45+ минут.

Этап 4: После развёртывания (непрерывно)

После развёртывания тестирование не прекращается. Проверки после развёртывания подтверждают, что приложение работает в реальном продакшен-окружении.

Что запускается здесь:

  • Дымовые тесты развёрнутого окружения (критические пользовательские сценарии)
  • Синтетический мониторинг (тесты по расписанию, имитирующие поведение пользователей)
  • Канареечный анализ (сравнение частоты ошибок между старой и новой версиями)
  • Эндпоинты проверки здоровья
# Example: Post-deploy smoke tests
smoke-tests:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 20
        cache: 'npm'
    - run: npm ci
    - run: npx playwright install --with-deps chromium
    - run: npx playwright test --project=smoke
      env:
        BASE_URL: https://production.example.com
    - name: Notify on failure
      if: failure()
      run: |
        curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
          -H 'Content-Type: application/json' \
          -d '{"text":"Production smoke tests failed after deploy!"}'

Распространённые ошибки в структуре тестов пайплайна

Запуск всего при каждом push

Если браузерные тесты запускаются при каждом push, разработчики ждут 20 минут обратной связи по однострочному исправлению. Запускайте на push только быстрые тесты; дорогие тесты сохраняйте для событий PR и слияния.

Пропуск интеграционного уровня

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

Недостаточно быстрый отказ

Если unit-тесты сломаны, не тратьте вычислительные ресурсы на запуск интеграционных и браузерных тестов. Используйте зависимости задач (needs), чтобы создать пайплайн, где каждый этап блокирует следующий.

Идентичные тесты на нескольких этапах

Если ваши интеграционные тесты уже проверяют API авторизации, браузерным тестам не нужно повторно тестировать авторизацию через API. Браузерные тесты должны фокусироваться на поведении UI, которое невозможно проверить на нижних уровнях.

Сопоставление типов тестов с этапами пайплайна

Тип тестов Этап Триггер Типичная длительность Назначение
Линтинг / Проверка типов 1 Каждый push 30с - 1мин Поиск синтаксических и типовых ошибок
Unit-тесты 1 Каждый push 30с - 3мин Проверка логики в изоляции
Интеграционные тесты 2 PR / слияние в develop 3 - 10мин Проверка взаимодействия компонентов
Контрактные тесты 2 PR / слияние в develop 1 - 5мин Проверка соответствия API-схем
Браузерные тесты 3 Слияние в main 5 - 20мин Проверка сквозных пользовательских сценариев
Визуальная регрессия 3 Слияние в main 3 - 10мин Обнаружение непреднамеренных изменений UI
Тесты производительности 3 Слияние в main 5 - 15мин Проверка бюджетов времени отклика
Дымовые тесты 4 После развёртывания 1 - 3мин Проверка критических путей в продакшене
Синтетический мониторинг 4 По расписанию 1 - 5мин Постоянный контроль здоровья продакшена

Практическое упражнение

  1. Сопоставьте ваш текущий набор тестов с четырьмя этапами пайплайна. На каком этапе находится каждый тип тестов? Есть ли пропущенные этапы?
  2. Измерьте длительность каждого этапа. Превышает ли какой-либо этап целевое время?
  3. Выявите тесты, которые запускаются на неправильном этапе (например, медленные тесты при каждом push)
  4. Создайте пайплайн с как минимум тремя этапами с зависимостями между задачами
  5. Убедитесь, что сбой на этапе 1 предотвращает запуск этапов 2 и 3