Делай как вGoogle
Скачать 5.77 Mb.
|
296 Глава 14. Крупномасштабное тестирование являются многопоточными и их охват обычно ограничивается тестируемым двоичным файлом. Тем не менее только они могут выявить снижение производительности в но- вых версиях и гарантировать, что система справится с ожидаемыми пиками трафика. С увеличением масштаба нагрузочного теста увеличивается объем входных данных, и в какой-то момент становится трудно генерировать высокую нагрузку, чтобы вы- звать ошибку. Способность справляться с высокой нагрузкой — это свойство системы, а не отдельных ее компонентов. Поэтому важно, чтобы тесты были максимально приближены к продакшену. Каждой SUT необходим тот же объем ресурсов, что и продакшену, чтобы уменьшить шум от повторения топологии продакшена. Одним из способов устранения шума в тестах производительности является из- менение топологии развертывания — распределения различных двоичных файлов в сети компьютеров. Машина, на которой выполняется двоичный файл, может вли- ять на характеристики производительности. Если в тесте, оценивающем различия в производительности, базовая версия работает на быстром компьютере (или на компьютере с быстрой сетью), а новая версия — на медленном, то результат может выглядеть как снижение производительности. Поэтому лучше запускать обе версии на одном и том же компьютере. Если одна и та же машина не может использоваться для тестирования обеих версий двоичного файла, калибруйте результаты, выполнив несколько прогонов и удалив пики и провалы. Тестирование конфигурации развертывания Тесты этого типа имеют следующие характеристики: y SUT: единственная герметичная машина или изолированное развертывание в облаке; y данные: нет; y проверка: с использованием утверждений (без сбоев). Часто источником дефектов является не код, а конфигурация: файлы данных, базы данных, определения параметров и т. п. Большие тесты могут проверить интеграцию SUT с файлами конфигурации, потому что эти файлы читаются во время запуска двоичного файла. На самом деле такие тесты являются проверкой «на дым» — они не требуют боль- шого количества дополнительных данных или уточнений. Если SUT запускается, тест считается пройденным, в противном случае — не пройденным. Исследовательское тестирование Тесты этого типа имеют следующие характеристики: y SUT: продакшен или общая промежуточная среда; y данные: импортируются из продакшена или из известного теста; y проверка: вручную. Типы больших тестов 297 Исследовательское тестирование 1 — это разновидность ручного тестирования, в кото- ром все внимание сосредоточено не на поиске изменений в поведении (при повторном тестировании известных сценариев использования), а на выявлении сомнительного поведения (при использовании новых сценариев). Обученные пользователи/тести- ровщики взаимодействуют с продуктом через общедоступный API, пытаясь найти новые сценарии использования системы, в которых ее поведение отличается от ожида- емого или интуитивно предполагаемого, а также уязвимости в системе безопасности. Исследовательское тестирование полезно как для новых, так и для давно действую- щих систем. Оно позволяет выявить неожиданное поведение и побочные эффекты. Благодаря тому что тестировщики следуют разными путями, доступными в системе, они могут увеличить охват системы и при выявлении ошибки создать новые авто- матизированные функциональные тесты. Эта разновидность тестирования напо- минает ручное «нечеткое тестирование» — своеобразную версию интеграционного функционального тестирования. Ограничения Ручное тестирование не масштабируется линейно; то есть для выполнения ручных тестов требуется, чтобы человек тратил свое время. Поэтому для любых дефектов, обнаруженных в ходе исследовательского тестирования, должны быть написаны автоматические тесты, которые можно будет запускать гораздо чаще. Охота за ошибками Одним из распространенных подходов, которые мы используем для ручного иссле- довательского тестирования, является охота за ошибками (bug bashes, https://oreil.ly/ zRLyA ). Команда инженеров и связанные с ней специалисты (менеджеры, менеджеры по продукту, инженеры-тестировщики — все, кто знаком с продуктом) планируют «встречу», на которой тестируют продукт вручную и озвучивают рекомендации относительно конкретных областей и/или отправных точек, заслуживающих внима- ния. Цель таких встреч в том, чтобы опробовать разные варианты взаимодействия для документирования случаев сомнительного поведения продукта и явных ошибок. Регрессионное A/B-тестирование Тесты этого типа имеют следующие характеристики: y SUT: два изолированных развертывания в облаке; y данные: обычно импортируются из продакшена или методом выборки; y проверка: A/B-сравнение. Юнит-тесты охватывают ожидаемые пути выполнения в небольшом фрагменте кода. Но ни для какого продукта невозможно предсказать все или большинство возможных вариантов сбоев. Кроме того, как гласит закон Хайрама, действительный общедо- 1 Whittaker J. A. Exploratory Software Testing: Tips, Tricks, Tours, and Techniques to Guide Test Design. New York: Addison-Wesley Professional, 2009. 298 Глава 14. Крупномасштабное тестирование ступный API — это не публично объявленные, а все видимые пользователю аспекты продукта. Поэтому неудивительно, что A/B-тесты являются наиболее распростра- ненной формой крупномасштабного тестирования в Google. Идея A/B-сравнения зародилась еще в 1998 году, и уже с 2001 года в Google его начали проводить для большинства наших продуктов, начиная с Ads, Search и Maps. В процессе выполнения A/B-тесты посылают трафик общедоступному API и срав- нивают ответы старой и новой версий (что особенно важно для миграций). Любые отклонения в поведении идентифицируются как ожидаемые или непредвиден- ные (регрессия). В этом случае SUT состоит из двух наборов реальных двоичных файлов: один представляет версию-кандидат, а другой — действующую базовую версию. Третий двоичный файл — это тест, который посылает трафик и сравнивает результаты. Есть и другие варианты этого подхода. A/A-тестирование (сравнение системы с са- мой собой) выявляет недетерминированное поведение, шум и нестабильность для их исключения из результатов A/B-тестирования. A/B/C-тестирование проводит сравнение последней рабочей версии, базовой сборки и новых изменений, чтобы показать не только влияние самих изменений, но и их последствия, которые про- явятся в следующей версии. A/B-тесты — это недорогой и легко автоматизируемый способ выявления неожи- данных побочных эффектов в любой действующей системе. Ограничения Тестирование различий сопряжено с несколькими сложностями, которые необхо- димо преодолеть: Оценка результатов Кто-то должен понимать результаты, чтобы распознавать ожидаемые различия. При тестировании различий не всегда ясно, являются ли различия хорошими или плохими (и действительно ли базовая версия действует правильно), поэтому A/B-тестирование включает шаги, выполняемые вручную. Шум Все, что вносит дополнительный шум в процесс тестирования различий, требует ручного исследования результатов. Это необходимо для устранения шума и яв- ляется одним из факторов, осложняющих создание хороших тестов различий. Охват Создание трафика, пригодного для тестирования различий, сложно готовить вручную. Тестовые данные должны охватывать широкий круг сценариев исполь- зования, чтобы помочь выявить редкие различия. Настройки Настройка и поддержка даже одной SUT довольно сложны. Создание сразу двух таких систем может удвоить сложность, особенно если они содержат взаимоза- висимости. Типы больших тестов 299 Приемочное тестирование пользователем Тесты этого типа имеют следующие характеристики: y SUT: единственная герметичная машина или изолированное развертывание в облаке; y данные: подготавливаются вручную; y проверка: с использованием утверждений. Юнит-тест пишет автор тестируемого кода. Это обстоятельство увеличивает вероят- ность, что недопонимание предполагаемого поведения продукта отразится не только на коде, но и на юнит-тестах: тест поможет убедиться, что код работает так, «как реализовано», а не «как задумано». Если у кода есть заказчик или представитель заказчика (коллегиальный орган или менеджер по продукту), полезно создать приемочные тесты — автоматические тесты, проверяющие продукт посредством общедоступного API на соответствие общего поведения определенным сценариям использования ( https://oreil.ly/lOaOq ). Есть несколько общедоступных фреймворков (например, Cucumber и RSpec), позволя- ющих создавать такие тесты на удобном для пользователя языке «выполняемых спецификаций». В Google для разработки автоматизированных приемочных тестов редко исполь- зуются языки спецификаций. Многие продукты Google созданы инженерами-про- граммистами, поэтому нет необходимости применять языки выполняемых специ- фикаций, если те, кто определяет предполагаемое поведение продукта, свободно владеют языками программирования. Зонды и канареечный анализ Тесты этого типа имеют следующие характеристики: y SUT: продакшен; y данные: продакшен; y проверка: с использованием утверждений и метрик A/B-тестирования. Зонды и канареечный анализ позволяют убедиться в нормальном функционировании продакшена. Они являются формой мониторинга, но структурно очень похожи на другие большие тесты. Зонды — это функциональные тесты, которые используют утверждения, касающиеся характеристик работы продакшена. Обычно эти тесты выполняют хорошо известные и детерминированные операции, осуществляющие доступ только для чтения, поэтому утверждения остаются действительными даже при изменении данных в продакшене. Например, зонд может обратиться к службе Google Search по адресу www.google.com и убедиться, что она возвращает результат, не проверяя его содержимого. В этом отношении зонды являются проверками «на дым», но при этом помогают выявлять основные проблемы продукта на ранних этапах разработки. 300 Глава 14. Крупномасштабное тестирование Канареечный анализ действует аналогично зонду, но выполняется, когда новая версия отправляется в продакшен. Если новая версия внедряется в производство поэтапно, есть возможность протестировать обновленные (канареечные) службы с помощью зондов и сравнить показатели работы канареечных и базовых частей продакшена, чтобы убедиться, что обновленные версии функционируют нормально. Зонды должны использоваться в любой действующей системе. Если процесс развер- тывания в продакшене включает этап, в ходе которого двоичный файл развертывается на ограниченном подмножестве реальных серверов (этап канареечного опробования), то канареечный анализ должен использоваться на этом этапе. Ограничения Любые проблемы, обнаруженные этими тестами (в продакшене), уже затронули конечных пользователей. Зонд, выполняющий действие, которое изменяет данные (запись), изменит состояние продакшена. Это может привести к одному из трех результатов: недетерминированное поведение среды и ошибки проверки утверждений, невозможность изменить данные в будущем или видимые пользователю побочные эффекты. Восстановление после аварии и проектирование хаоса Тесты этого типа имеют следующие характеристики: y SUT: продакшен; y данные: продакшен и подготовленные пользователем (для внедрения ошибки); y проверка: вручную и с использованием метрик A/B-тестирования. Эти тесты проверяют реакцию системы на неожиданные изменения или сбои. В течение многих лет в Google ежегодно проводятся «учения» под названием DiRT (Disaster recovery testing — «тестирование восстановления после отказа», https://oreil.ly/17ffL ), во время которых мы внедряем в нашу инфраструктуру ошибки почти в планетарном масштабе. Мы моделируем самые разные ситуации — от пожа- ров в вычислительном центре до злонамеренных атак. Однажды мы смоделировали землетрясение, которое полностью изолировало нашу штаб-квартиру в Маунтин- Вью (штат Калифорния) от остальных подразделений компании. Это помогло выявить не только технические недостатки, но и проблемы управления, когда все ключевые лица, принимающие решения, оказались недоступны 1 DiRT-тесты требуют четкой координации действий сотрудников всей компании. Проектирование хаоса, напротив, — это скорее «непрерывное тестирование» тех- нической инфраструктуры. Инженерия хаоса, ставшая популярной благодаря 1 Во время проведения этого теста практически ничего нельзя было делать, поэтому многие сотрудники пошли в одно из наших многочисленных кафе. Так мы создали DDoS-атаку на наши команды! Типы больших тестов 301 Netflix ( https://oreil.ly/BCwdM ), включает разработку программ, которые постоянно вводят ошибки в системы и наблюдают за их последствиями. В целом инструменты тестирования хаоса предназначены для контроля восстановления функциональности. Цель проектирования хаоса — помочь командам перестать уповать на стабильность и надежность своих продуктов и поднять отказоустойчивость кода на новый уро- вень. Команды в Google выполняют тысячи тестов хаоса каждую неделю, используя нашу систему Catzilla. Спровоцированные отказы и тесты с негативным влиянием используются для повы- шения уровня отказоустойчивости в действующих реальных системах, для которых цена и риски таких испытаний допустимы. Ограничения Любые проблемы, обнаруженные этими тестами (в продакшене), уже затронули конечных пользователей. Тестирование восстановления после отказа довольно дорого в управлении, поэтому мы проводим скоординированные учения не очень часто. Имитируя аварии такого уровня, мы фактически причиняем массу неприятностей своим сотрудникам и не- гативно влияем на их работу. Оценка действий пользователей y SUT: продакшен; y данные: продакшен; y проверка: вручную и с использованием метрик A/B-тестирования. Тестирование в продакшене позволяет собирать данные о поведении пользователей. У нас есть несколько альтернативных способов сбора метрик, характеризующих востребованность продута и проблемы с новыми особенностями. Внутренняя оценка Существуют технологии для создания ограниченного количества развертываний и экспериментов, позволяющие открыть доступ к новым особенностям только узкому кругу пользователей, например нашим сотрудникам (для внутренней оценки), и получить обратную связь в реальном окружении. Проведение экспериментов Доступ к новым экспериментальным возможностям открывается подмноже- ству пользователей без их ведома. Затем поведение экспериментальной группы сравнивается с поведением контрольной группы по некоторым укрупненным показателям. Например, мы провели на базе YouTube эксперимент, связанный с изменением способа обработки лайков к видеороликам (отключив возмож- ность оставлять дизлайки), и только ограниченный круг пользователей видел это изменение. 302 Глава 14. Крупномасштабное тестирование Это важная возможность для Google ( https://oreil.ly/OAvqF ). Одна из первых историй, которую нуглеры слышат при поступлении к нам на работу, связана с экспериментом по изменению цвета затемнения фона в объявлениях AdWords в Google Search. В результате этого эксперимента пользователи из эксперимен- тальной группы выполнили значительно больше переходов по объявлениям, чем пользователи контрольной группы. Экспертная оценка Эксперты получают результаты некоторого изменения, выбирают «лучшие» результаты и объясняют свой выбор. Затем на основе их отзывов определяется, является ли изменение положительным, нейтральным или отрицательным. На- пример, Google уже давно привлекает экспертов для оценки качества обработки поисковых запросов (мы даже опубликовали рекомендации по оцениванию). В некоторых случаях отзывы с рейтинговыми оценками помогают определить уместность внесения исследуемых изменений в алгоритм. Экспертная оценка имеет решающее значение для недетерминированных систем, таких как системы машинного обучения, в которых нет четкого критерия качества. Большие тесты и рабочий процесс разработчика Мы поговорили о том, что такое большие тесты, зачем, когда и как часто их нужно проводить, но мы почти не затронули вопрос «кто». Кто пишет тесты? Кто проводит тесты и исследует причины сбоев? Кто владеет тестами? И как сделать тестирование менее утомительным? Стандартная инфраструктура юнит-тестирования может быть непригодной для больших тестов, и все же важно интегрировать большие тесты в рабочий процесс разработчика. Один из способов сделать это — создать механизмы автоматического выполнения тестов до и после отправки изменений в репозиторий. Многие большие тесты в Google не вписываются в структуру TAP, поскольку они негерметичные, нена- дежные и ресурсоемкие. Но мы должны гарантировать их выполнение, иначе рискуем пропустить важный сигнал и усложнить устранение проблем. Поэтому мы отдельно выполняем непрерывную сборку после отправки кода в репозиторий и рекомендуем выполнять эти тесты перед отправкой, чтобы получить обратную связь от автора. Также в рабочий процесс можно включить A/B-тесты. Перед отправкой в репози- торий они могут проверять факт проведения обзора кода и утверждение различий в пользовательском интерфейсе. Один из таких наших тестов автоматически блоки- рует выпуск новой версии, если в коде есть неутвержденные различия. Иногда тесты настолько велики или требовательны к ресурсам, что их выполнение перед отправкой кода вызывает слишком много сложностей. Поэтому такие тесты выполняются после отправки и дополнительно включаются в процесс выпуска новой версии. При этом в монолитный репозиторий могут проникнуть ошибки и потребу- ется найти и откатить изменения, которые к ним привели. Мы ищем компромиссы Большие тесты и рабочий процесс разработчика 303 между сложностью для разработчика, задержками в передаче изменений и надеж- ностью непрерывной сборки. Разработка больших тестов Структура больших тестов довольно стандартная, но их создание все равно сопря- жено с трудностями, особенно для новичков. При разработке таких тестов нужно иметь под рукой ясные библиотеки, документа- цию и примеры. Юнит-тесты легче писать благодаря поддержке используемого языка программирования (когда-то фреймворк JUnit считался экзотикой, но в настоящее время получил широкое распространение). Мы повторно используем одни и те же биб- лиотеки утверждений для функциональных и интеграционных тестов и со временем создали библиотеки для взаимодействия с SUT, помогающие запускать A/B-тесты, генерировать тестовые данные и организовывать рабочие процессы тестирования. Большие тесты дороги в сопровождении с точки зрения как ресурсов, так и време- ни, но не все большие тесты одинаковы. Одна из причин популярности A/B-тестов состоит в том, что они не требуют больших затрат на выполнение этапа проверки. Аналогично тестирование в продакшене обходится дешевле, чем создание изоли- рованных и герметичных SUT. Различия в затратах на разные виды тестов с учетом сопровождения инфраструктуры и кода могут оказаться весьма существенными. Однако все эти затраты необходимо рассматривать вместе. Если затраты на согласо- вание различий вручную или поддержку и безопасность тестирования в продакшене перевешивают выгоды от тестов, то такие тесты не будут эффективными. |