Особенности тестирования Facebook

Среди вопросов к предыдущей колонке был один об особенностях тестирования. Мой коллега Джастин Бишоп недавно описал некоторые подробности тестирования и детали миграции с Watir на Webdriver. Вопрос тестирования трудно рассматривать в отрыве от вопроса выкатки кода, и в качестве факультативного задания могу посоветовать это видео от релиз-инженера Facebook.

Рабочая среда программиста в Facebook в далекие времена содержала аккаунт на сервере с клиентом под svn. С течением времени, потоком новых сил и растущей потребностью работать над своими экспериментами рабочая среда программиста эволюционировала в выделенный сервер и клиент под Git. О преимуществах и недостатках Git можно почитать на других ресурсах, среди достоинств этого инструмента конкретно внутри Facebook чаще всего называют скорость создания новой ветки (сайт у нас большой, и создание его копии под svn занимало немало времени) и волшебство git bisect, позволяющее довольно быстро увидеть, чей именно коммит сломал дизайн либо функционал.

Для тестирования функциональности используется phpUnit, и чаще всего новый модуль будет содержать пакет базовых тестов. Перед генерацией диффа для Фабрикатора изменение даже одной строчки кода в конкретном модуле повлечет за собой прогон всех нужных тестов на выделенном сервере разработчика. Это наверняка не самое оптимальное решение — даже несмотря на параллельное исполнение процессов phpUnit, прогон всех тестов для довольно масштабного диффа вполне может занять минут 20 и больше. Взамен получаешь уверенность, что внесенные изменения не сломали некоторые модули, о тестировании которых разработчик мог забыть (OpenGraph API, 0.facebook.com, мобильная версия сайта).

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

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

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

Некоторые тесты требуют весьма специфического состояния аккаунта пользователя — скажем, в случае логинов с подозрительных IP-адресов, пользователю предлагается ответить на секретные вопросы либо подтвердить свой аккаунт через SMS. Для этого большинство тестов использует созданные специально для этой цели аккаунты, которые живут в специальной базе данных, дружат только с другими тестовыми аккаунтами, никогда не появляются в «Людях, которых Вы можете знать» и никак не влияют на статистику сайта.

Для проверки отображения сайта в броузере используется Watir и тесты, написанные на Ruby. Заметка Джастина говорит о том, что вскоре планируется миграция на WebDriver и написание броузерных тестов в PHP. В остальном же тесты интерфейса мало чем отличаются от тестов функциональности — среди них тоже выделяются те, которые блокируют релиз в случае ошибки, они тоже зачастую привязаны к тестовым пользователям и сообщения об ошибках тоже ложатся в рассылки.

Если же говорить о том, чего не хватает, то пятизвездочный буфет инструментов для Web-тестирования с переходом в мобильный мир превращается в скудный ассортимент привокзальной столовой.
Проблема обостряется ввиду миграции пользователей социальных сетей на мобильные устройства, где уже сегодня в ряде стран мы отмечаем снижение времени, проведенного на ПК с увеличением мобильных сессий. Некоторые нетривиальные проблемы тестирования в этом новом мире:
  • Непостоянство соединений на 3G-сетях. Если Web-разработчик может более-менее рассчитывать на завершение XMLHTTPRequest, то пользователь мобильной сети между send() и onReadyStateChange() вполне мог заехать в туннель и потерять связь. Показывать ему прогресс загрузки при этом бесполезно. Эмулировать такое поведение, будучи в офисе, весьма трудно.
  • Телефоны постарше. Их можно тестировать с пакетом инструментов от DeviceAnywhere, но процесс трудно назвать эффективным. Кроме того, извечная задача разработчика — это тестировать код до его выкатки на сайт, а не после. Когда код лежит внутри корпоративной сетки, то нужна архитектура для вывода альфа-версий сайта на тестовые устройства.
  • WAP-шлюзы, адаптирующие контент под требования оператора. Даже если проблема тестирования под базовые модели телефонов решена, многие операторы считают нужным самостоятельно обрабатывать контент в интересах пользователя. Набор вспомогательных сервисов может включать свое понимание SSL, свой сервер для проксирования «печенек» броузера, свои взгляды на поддержку Ajax и использование CSS-спрайтов, которые иногда идут в разрез с декларируемыми возможностями телефона. Получателем жалоб пользователей в случае самодеятельности оператора чаще всего выступает сайт.
  • SMS. Короткие сообщение легко генерировать в плане генерации, но автоматизировать процесс «от и до» весьма трудно. В идеале сервер отсылал бы SMS на сотню-другую проверочных номеров, проверял статус SMPP-сервера получателя, после чего верифицировал бы собственно доставку на SIM-карту получателя.
  • Популярное

10 комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Тяжело живется ПХПшникам. Столько велосипедов еще изобрести надо.

Интересно было бы почитать про используемые подходы к решению

нетривиальные проблемы тестирования в этом новом мире

Вапросы:
— какого рода тесты вы используете: юнит, функциональные, интеграционные
— какой бы цифрой ты бы охарактеризовал покрытие кода тестами
— как построена инфраструктура тестов: например разворачиваете снапшет базы перед каждым тестом? Используете ли какие то решения для отслеживания зависимостей что бы выяснить какие тесты запускать(не все же каждый раз)?
— делаете ли нагрузочное тестирование с целью отслеживания регрессий, и какие инструменты используете? ВебДрайвер?
— какие либы используете для юнит тестов для разных языков: пхп, ц++, джава, эрланг, етк.
— используете ли анализаторы кода для отслеживания отклонений от style guidelines и ошибок, если да, то какие
— на каких тулах у вас построен continuous integration, если построен

— наверняка используете экспериментальное тестирование, как отслеживаете возможные ошибки? Ищите эксепшны в логах или что-то более продвинутое?

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

какого рода тесты вы используете: юнит, функциональные, интеграционные

Все из вышеперечисленного.

какой бы цифрой ты бы охарактеризовал покрытие кода тестами

Трудно сказать, поскольку есть, скажем, один цельный кусок (сайт на PHP), а есть куча вспомогательных сервисов, типа сервер поиска, ранжирования рекламы и т.д. Всякие критические вещи, типа API, покрыты на 100%.

как построена инфраструктура тестов: например разворачиваете снапшет базы перед каждым тестом? Используете ли какие то решения для отслеживания зависимостей что бы выяснить какие тесты запускать(не все же каждый раз)?

Юнит-тесты лежат в той же директории, что и код, который они тестируют. Инструмент для генерации диффа знает, что прежде чем что-то отсылать на рецензию коллег, нужно прогнать все тесты из соответствующих папок ’tests’. Это на личном сервере разработчика. Специальные тестовые серверы гоняют 100% тестов на постоянной основе, так как системные ошибки не интересны разработчику, но интересны сисадминам.

делаете ли нагрузочное тестирование с целью отслеживания регрессий, и какие инструменты используете? ВебДрайвер?

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

используете ли анализаторы кода для отслеживания отклонений от style guidelines и ошибок, если да, то какие

Да, внутренний инструмент поддерживает кучу линтеров www.phabricator.com/...rcanist/#linter

наверняка используете экспериментальное тестирование, как отслеживаете возможные ошибки? Ищите эксепшны в логах или что-то более продвинутое?

Там в видео от Чака рассказывается подробнее, но релиз вначале выкатывается на небольшое количество серверов. К этому набору прикручен свой аггрегатор логов, созерцанием которого разработчики и заняты во время релиза.

Юнит-тесты лежат в той же директории, что и код, который они тестируют.
Я имел в виду следующую ситуацию: предположим ты пишешь код который потом инклудят и используют другие компоненты, тогда при комите кода целесообразно запускать не только юнит тесты твоей либы, но и тесты для компонентов которые имеют зависимость на твою либу. В некоторых организациях где я работал так и сделано — комит вызывает тригер, который прослеживает зависимости и запускает тесты зависимых либ в том числе что бы ничего не поломалось.
С нагрузочным сложнее, так как эмулировать такой уровень нагрузки в искусственных условиях трудно.
Помоему вполне реально — выделенный сервер с тестируемым билдом, запустили тесты, посмотрели временные метрики сравнили со старыми из базы, увидели есть ли где регрессия. Все вполне автоматизируется.

Да, я тогда не так понял насчет первого. Так и происходит — у нас нет пхп’шного __autoload__, и каждый задействованный модуль нужно прописывать самостоятельно, но потом Arcanist смотрит на граф зависимостей.

Насчет второго, думал, что речь идет о *высоко*нагрузочном тестировании на девятизначное количество пользователей. Если же просто об отслеживании регрессий, то в видео Чак говорит о таком инструменте, называется PerfLab, здесь кто-то проконспектировал его ролик ablogaboutcode.com/...d-push-process но он по сути примерно то и делает.

Спасибо, очень интересно было почитать. Если не трудно, пишите еще:).

Кидайте вопросы, на абстрактные темы трудно писать.

Напиши как устроена УДБ, как делается решардинг, кроссдатацентрная репликация.

Для этого большинство тестов использует созданные специально для этой цели аккаунты, которые живут в специальной базе данных
А в какой базе живут основные аккаунты? И как вообще генерируются данные для тестов?

Подписаться на комментарии