Тестирование на скорость в Гугл

8 Янв
2012

Данный пост — перевод занимательной статье, опубликованной инженерами GoogleTesting at the speed and scale of Google

Системы непрерывной сборки играют ключевую роль в сохранении работоспособности программного обеспечения в процессе его разработки. Базовые шаги большинства систем непрерывной сборки:
  1. Получить последнюю версию исходного кода.
  2. Запустить все тесты.
  3. Сообщить о результатах.
  4. Повторить 1-3.

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

Разработка программного обеспечения в Гугл большая и быстрая. Исходный код получает 20+ изменений в минуту и 50% файлов изменяются каждый месяц! Каждый продукт разрабатывается и выпускается из ‘head’ и зависит от автоматических тестов, проверяющих его работу. Частота выпуска изменяется от нескольких раз в день до одного раза в неделю и зависит от команды.

С большим количеством быстро изменяющегося исходного кода, команды разработчиков могут застревать и тратить много времени только для сохранения их сборок “зелёными”. Системы непрерывной сборки должны вместо диапазона подозрительных измений или создания растянутого бинарного дерева проблемного изменения, помогать, указывая конкретное изменение, на котором тест перестал выполняться. Для нахождения конкретного изменения, которое сломало тест, мы можем запускать каждый тест на каждом изменении, но это будет очень дорого.

Для решения этой проблемы, мы сделали систему непрерывной сборки, использующую анализ зависимостей для определения всех тестов, которые завтрагиваются изменением, и запускающую только эти тесты для каждого изменения. Система собирается на верхнем уровне инфраструктуры облачных вычислений Гугл и поддерживает много сборок для одновременного исполнения, а так же позволяет системе запускать затронутые тесты сразу же после принятия изменений.

Вот пример, где наша система может обеспечивать более быструю и точную обратную связь, нежели традиционная непрерывная сборка. В этом сценарии два теста и три изменения, которые затрагивают эти тесты. Gmail_server_tests сломаны вторым изменением, тем не менее привычная система непрерывной сборки сможет сказать лишь то, что изменение #2 или изменение #3 сломали этот тест. Использую параллельную сборку, мы можем запустить тесты, не дожидаясь окончания текущего цикла сборки/тестирования. Анализ зависимостей ограничивает количество тестов, запускаемых для каждого изменения, поэтому в данном примере итоговое количество выполняемых тестов такое же, как и раньше.

image

Давайте заглянем глубже в процесс анализа зависимостей.

В памяти мы поддерживаем графы крупно-модульных зависимостей между различными тестами и правилами сборки в памяти для всего исходного кода. Этот граф, несколько Гб в памяти, остаётся актуальным с каждым принятым изменением. Это позволяет нам транзитивно определять все тесты, которые зависят от кода, модифицированного в выбранном изменении, и которые нужно запустить для определения текущего состояния сборки. Давайте посмотрим на пример.

Рассмотрим два проекта, каждый содержит разный набор тестов:

image

Граф зависимостей сборки выглядит следующим образом:

image

Мы можем увидеть как два изолированных куска кода изменяются на различной глубине дерева зависимостей и как они анализируются для определения затронутых тестов, которые являются минимальным набором тестов, запускаемых для того, чтобы убедиться в “зелёном” цвете Gmail и Buzz.

Пример1: Изменение в общей библиотеке

Для первого сценария, рассмотрим изменение, модифицирующее файлы в common_collections_util.

image

Как только это изменение принято, мы начинаем поиск в ширину для определения всех зависящих от него тестов.

image

После нахождения прямых зависимостей, продолжаем поиск в ширину для определения всех транзитивных зависимостей, пока не будут достигнуты все краевые узлы.

image

После окончания, мы знаем все тесты, которые нужно запустить, и можем посчитать проекты, которым нужно обновить свой общий статус, основанный на этих тестах.

image

Пример2: изменение в зависимом проекте:

Изменение, модифицирующее файлы в youtube_client, принято.

image

Мы начинаем такой же анализ и понимаем, что только buzz_client_tests затронуты и статус проекта Buzz нуждается в обновлении:

image

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

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

— Пуджа Гупта, Марк Иви и Джон Пеникс
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх