Монорепозитории стали предпочтительной стратегией организации кода во многих крупнейших технологических компаниях. По данным Google, Microsoft и Meta, все три компании успешно управляют десятками тысяч проектов в единых репозиториях, при этом монорепозиторий Google содержит более 2 миллиардов строк кода. По данным опроса JetBrains 2023, 34% профессиональных разработчиков работают в монорепозиторных средах, по сравнению с 12% в 2019 году — под влиянием таких инструментов как Nx, Turborepo и Bazel. Тестирование в монорепозиториях уникально: изменения в общей библиотеке могут затронуть десятки приложений.

TL;DR: Тестирование в монорепозитории требует обнаружения затронутых тестов (запускай только тесты для пакетов, затронутых изменением), шардирования тестов (распределяй тесты по параллельным воркерам) и кэширования сборок. Используй Nx или Turborepo для обнаружения затронутых пакетов.

Понимание вызовов тестирования Monorepo

Традиционные стратегии тестирования мульти-репозиториев не масштабируются для monorepos. Ключевые вызовы включают:

Вызовы масштаба

Объем кода:

  • Единый репозиторий с 50+ проектами
  • Миллионы строк кода
  • Тысячи зависимостей
  • Сложные взаимозависимости

Размер тестового набора:

  • 10,000+ тестовых файлов
  • 100,000+ отдельных тестов
  • Часы времени выполнения
  • Массовое потребление ресурсов

Влияние изменений:

  • Один commit затрагивает множество проектов
  • Каскадные требования к тестированию
  • Сложно определить, что тестировать
  • Риск чрезмерного или недостаточного тестирования

Вызовы производительности

Времена сборки:

  • Полные сборки, занимающие 60+ минут
  • Разработчики ждут часами feedback от CI
  • Сниженная продуктивность
  • Overhead переключения контекста

Использование ресурсов:

  • Сотни одновременных CI задач
  • Дорогостоящие затраты на вычисления
  • Насыщение пропускной способности сети
  • Требования к хранилищу для артефактов

“In a monorepo, the biggest testing trap is running everything on every commit. The goal is zero unnecessary test runs — only test what could possibly be broken by this change, and test it thoroughly.” — Yuri Kan, Senior QA Lead

Фундаментальные стратегии

1. Обнаружение затронутых проектов

Тестируйте только то, что изменилось [подобный JavaScript код]

2. Инкрементное тестирование

Используйте кэширование для избежания повторного тестирования неизменившегося кода [подобный YAML код]

3. Умная приоритизация тестов

Запускайте критичные тесты первыми [подобный TypeScript код]

Продвинутые техники

Распределенное выполнение тестов

Параллелизируйте на нескольких машинах [подобный YAML код]

Умное кэширование сборки

Кэширование на нескольких уровнях [подобный TypeScript код]

Анализ влияния тестов

Предсказывайте, какие тесты вероятно упадут [подобный Python код]

Примеры из реального мира

Подход Google: Bazel

Google использует Bazel для monorepo сборок с:

Возможностями:

  • Точное отслеживание зависимостей
  • Герметичные сборки (полностью воспроизводимые)
  • Агрессивное кэширование
  • Распределенное выполнение

Результаты:

  • Миллиарды строк кода
  • Тысячи разработчиков
  • Среднее время сборки: < 10 минут
  • Процент попаданий в кэш: > 90%

Microsoft: Git Virtual File System (GVFS)

Microsoft разработал GVFS для репозитория Windows:

Статистика:

  • 3.5 миллиона файлов
  • Репозиторий 300+ GB
  • 4,000+ инженеров
  • Виртуализированная файловая система для масштаба

Meta (Facebook): Buck2

Оптимизации системы сборки Meta:

  • Инкрементные сборки
  • Удаленное выполнение
  • Интеллектуальный выбор тестов
  • Параллельное выполнение

Влияние:

  • 90% сокращение времени тестирования
  • Feedback менее минуты для большинства изменений
  • Массовая экономия затрат

Лучшие практики

1. Установите четкие границы проектов

monorepo/
├── packages/
│   ├── api/              # Backend API
│   ├── web-app/          # Frontend app
│   ├── mobile/           # Mobile app
│   └── shared/           # Shared utilities
├── tools/                # Build tools
└── tests/
    ├── unit/             # Fast unit tests
    ├── integration/      # Integration tests
    └── e2e/              # E2E tests (expensive)

2. Внедрите прогрессивное тестирование

stages:

  - name: Fast Tests
    tests: [lint, unit]
    timeout: 5min
    on_failure: block_merge

  - name: Integration Tests
    tests: [integration]
    timeout: 15min
    requires: Fast Tests

  - name: E2E Tests
    tests: [e2e]
    timeout: 30min
    requires: Integration Tests

3. Мониторьте здоровье тестов

Отслеживайте метрики здоровья тестов: среднюю продолжительность, частоту нестабильности, процент попаданий в кэш, эффективность параллелизации.

Заключение

Тестирование monorepo требует сложных стратегий, выходящих за рамки традиционных подходов к тестированию. Внедряя обнаружение затронутых проектов, инкрементное тестирование, умную приоритизацию и распределенное выполнение, вы можете поддерживать быстрые циклы обратной связи даже по мере роста вашего monorepo.

Ключевые выводы:

  1. Тестируйте только то, что изменилось—используйте обнаружение затронутых проектов
  2. Кэшируйте агрессивно на всех уровнях
  3. Распределяйте тесты интеллектуально по runners
  4. Приоритизируйте критичные тесты для быстрой обратной связи
  5. Мониторьте и постоянно оптимизируйте производительность тестов

План действий:

  • Внедрите обнаружение затронутых проектов на этой неделе
  • Добавьте инкрементное тестирование с кэшированием
  • Настройте распределенное выполнение тестов
  • Мониторьте метрики здоровья тестов
  • Пересматривайте и оптимизируйте ежемесячно

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

Помните: Цель не в том, чтобы тестировать меньше, а в том, чтобы тестировать умнее. С правильными стратегиями ваш monorepo может обеспечивать более быструю обратную связь, чем множественные репозитории, при сохранении комплексного тестового покрытия.

Смотрите также

Официальные ресурсы

FAQ

Что такое обнаружение затронутых тестов в монорепозитории?

Обнаружение затронутых тестов определяет, какие пакеты и их нижестоящие зависимости затронуты данным изменением кода, чтобы запускать только их тесты. Инструменты типа Nx используют граф зависимостей для расчёта затронутого набора.

Как настроить шардирование тестов в CI-пайплайне?

Разбивай тесты на параллельные задания по количеству тестов или времени выполнения. Nx Cloud и Turborepo Remote Cache поддерживают интеллектуальное распределение задач. Для GitHub Actions используй matrix strategy с переменными SHARD и TOTAL_SHARDS.

Каковы сложности E2E тестирования в монорепозиториях?

E2E тесты в монорепозиториях сталкиваются с: координацией версий пакетов для совместного тестирования, оркестрацией зависимых сервисов для каждого E2E теста и изоляцией E2E тестов при совместном использовании баз данных.

Как обеспечить изоляцию тестов между пакетами?

Используй отдельные тестовые базы данных на пакет, избегай глобального состояния в общих утилитах, используй dependency injection вместо синглетонов уровня модуля и запускай тесты пакетов в отдельных процессах.

See Also