company_banner

Как мы тестируем взаимодействие с Facebook



    Вступление

    Привет, хаброжитель! Уже довольно давно я хотел написать статью о том, как у нас в Badoo устроена автоматизация тестирования. Хотелось написать о чем-то интересном и, в то же время, полезном. Поделиться опытом, который можно было бы легко интегрировать почти в любую систему. И вот, такая тема назрела…

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

    Для верификации пользователей у нас существует много различных способов. Некоторые из них довольно привычные, такие, как верификация по номеру телефона. Есть и более необычный — верификация по фотографии. Но самая простая и быстрая — верификация через социальные сети.

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

    Сегодня я расскажу о том, как на Badoo устроена регистрация и верификация через Facebook и о том, как мы научили selenium-тесты ее проверять.





    Итак, представим, что вы — новый пользователь сервиса Badoo. Вы заходите на сайт и видите вот такую форму регистрации. Заполнять все эти поля или кликнуть по кнопочке регистрации через Facebook? Для меня это — никогда не вопрос. Я бы заполнил все поля вручную и не стал бы привязывать свой аккаунт. Почему? Потому что я немного параноик, надеюсь, это не заразно. :)

    На самом деле Badoo никогда не разместит какую-либо информацию из стороннего источника без согласия пользователя, так что спокойно кликаем по темно-синей кнопке и регистрируемся на сайте. Один клик, 10-15 секунд, и у нас есть свой верифицированный профиль на Badoo. Ура!



    Как бы поступил настоящий QA-инженер после того, как создал профиль на сервисе так просто и быстро? Правильно, попробовал бы создать еще один. Как отреагирует сервис, если на тот же FB-аккаунт попробовать зарегистрировать еще один профиль?

    Снова открываем страничку регистрации и кликаем по иконке FB. Ничего неожиданного не произошло, Badoo “узнало” FB-аккаунт и вместо регистрации сразу авторизовало. Все в порядке.

    Первый selenium-тест на регистрацию

    Теперь представим, что вы — QA-инженер в компании Badoo. Перед вами стоит задача — автоматизировать флоу регистрации и авторизации через FB аккаунт. На первый взгляд задача простая, вот что вам понадобится:

    • аккаунт FB;
    • локатор кнопочки FB на странице регистрации;
    • метод, который ждет авторизационную cookie (чтобы убедиться, что тест залогинился на сайте);
    • локатор sign out кнопочки, чтобы разлогиниться;
    • метод, который ждет, когда авторизационная cookie пропадет.


    После того, как были написаны необходимые методы, составляем сценарий:

    • Открыть стартовую страницу;
    • Кликнуть иконку Facebook’а;
    • В открывшейся вкладке авторизоваться на Facebook;
    • Дождаться авторизации на Badoo;
    • Получить id пользователя (пусть будет first_user_id);
    • Разлогиниться;
    • Открыть стартовую страницу;
    • Кликнуть иконку Facebook’a;
    • Дождаться авторизации на Badoo;
    • Получить id пользователя (пусть будет second_user_id);
    • Убедиться, что first_user_id и second_user_id совпадают.


    Итак, сценарий готов, вы запустили тест и он прошел. Все прекрасно. Самое время вставить котика в статью:



    Коммитим код теста в ветку, кидаем задачу на ревью и идем пить кофе. Однако, не успели вы дойти до кухни, как приходит уведомление — задача не прошла ревью, тест не работает. Что-то пошло не так…

    После перезапуска теста становится ясно, что проблема в следующем — у данного FB-аккаунта уже существует профиль на Badoo. Вместо регистрации тест сразу авторизовался. Делать нечего, надо удалять профиль по завершению теста. Слава Богу, у нас есть потрясающая штука — QaApi!

    Несколько лет назад я рассказывал, как она интегрирована с нашими автотестами. Доклад назывался «Selenium тесты. От RC и одного пользователя к WebDriver, Page Object и пулу пользователей», найти его можно тут — habrahabr.ru/company/badoo/blog/216255.

    Если коротко, это внутренний api, на который из теста можно отправить запрос и совершить некоторые манипуляции на стороне приложения. Вызывается он довольно просто:

    QaApiHelper::deleteUser(user_id);
    


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

    Когда тест научился удалять пользователя за собой, он стал работать стабильно и прекрасно. Но так было не долго.

    Этапы тестирования Badoo

    О том, какие этапы тестирования существуют в нашей компании, мы рассказываем практически на каждой конференции. Здесь я перечислю коротко те, которые интересны с точки зрения selenium-тестов:
    • Тестирование на девел-окружении. Девел — это копия продакшена со своими базами и внутренними сервисами.
    • Тестирование на шоте. Шот — это продакшен-окружение, доступное из внутренней сети по определенному урлу и являющееся мержем кода мастера и тестируемой задачи.
    • Тестирование на стейджинге. Стейджинг, традиционно — это результат мержа ветки релиза и мастера.
    • Тестирование на продакшене.


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

    Второй selenium-тест на регистрацию

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

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


    Как решить нашу проблему? Как сделать так, чтобы у теста всегда был свежий пользователь FB?

    Сначала я попытался решить проблему минимально просто. Создал mysql-табличку, в которую внес несколько созданных руками FB-пользователей и проставил им статусы — свободны. Тест брал пользователя из этой таблички, меняя ему статус на “занят”. Если свободного пользователя не было, тест падал с соответствующим сообщением.

    У этой системы было несколько очевидных минусов. Прежде всего, если одновременно запускалось слишком много инстансов теста, аккаунтов не хватало и взять их было неоткуда. Также тест мог по какой-то причине не освободить пользователя в конце (например если он был остановлен нажатием “Ctrl+C”). Ничто из этого не радовало по утрам, когда до релиза оставалось меньше часа.



    Довольно быстро устав от нестабильных падений и неконтролируемых состояний FB-аккаунтов, я начал искать решение получше…

    The Graph API

    У Facebook есть замечательный api, который позволяет создавать тестовых пользователей и манипулировать ими — developers.facebook.com/docs/graph-api. Организована она довольно просто: мы формируем необходимый запрос и посылаем его на сервер FB, ответ возвращается в формате json.

    Пример запроса, который зарегистрирует тестового пользователя с именем Alex:

    https://graph.facebook.com/{APP_ID}/accounts/test-users?name=Alex&access_token={APP_ID}|{SECRET}


    Application id и secret мы получаем, регистрируя наше приложение на FB (подробнее тут — developers.facebook.com/docs/facebook-login/overview).

    Настоящий пул Facebook пользователей

    Что ж, давайте создавать пользователей! :)



    Внимательно изучив graph-api и его особенности, мы составили список нюансов:

    • Количество регистраций на одно приложение ограничено. Цитата: “Для каждого приложения можно создать не более 2000 тестовых пользователей.”.
      Вывод: нужно вести учет созданных пользователей.
    • Только что созданный тестовый пользователь может взаимодействовать только с единственным приложением. В данном случае приложение — это домен, на котором разместился сервис. В Badoo стейджинг и шоты находятся на разных доменах.
      Вывод: ведя учет пользователей, необходимо их разделять по app id.
    • Пользователь регистрируется довольно медленно. В среднем от 2 до 5 секунд.
      Вывод: удобнее иметь заранее созданного пользователя FB, чтобы тест не тратил время на его создание.
    • Тест должен иметь дело с тем аккаунтом, который наверняка не используется в каком-то еще тесте, чтобы избежать флуктуационных race condition.
      Данный пункт важен в рамках описываемого здесь теста.


    Итого: было бы круто иметь кастомный пул пользователей FB, который соответствовал бы нашим “хотелкам”. По сути это должна быть табличка, которая будет содержать следующую информацию:
    • Id пользователя;
    • Email;
    • Password;
    • App id;
    • App Secret;
    • Состояние пользователя — занят тестом или нет;
    • Timestamp создания пользователя.


    В дополнение к этой табличке нам понадобилось несколько скриптов.

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

    Второй решает проблему долгого создания пользователя на стороне facebook. Выглядит это следующим образом:


    Получение FB-пользователя мы обернули в специальный QaApi метод. Тест обращается к нему за свободным пользователем. Если такого нет, создается специальное задание. В рамках этого задания скрипт посылает curl-запрос к graph-api, дожидается ответа и записывает в табличку нового пользователя. Тест же получает ответ — “необходимо подождать”, закрывает коннект и делает еще одну попытку спустя несколько секунд. Таким образом мы решили две проблемы. Во-первых, логика работы с graph-api отделена от логики тестов. Во-вторых, тесты не держат долгие коннекты к сторонним сервисам, что существенно облегчает дебаг любых проблем, связанных с увеличением времени прохождения тестов.

    Далее мы переписали необходимые тесты на новую систему получения FB аккаунтов и оставили тесты гоняться на ночь с нашем CI-сервером (мы используем Teamcity). К утру результат был готов. Создалось ровно столько пользователей, сколько было необходимо для использования в тестах.

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

    А есть ли такой удобный API у других социальных сетей?

    Я интересовался у ребят из ВКонтакте:


    И у ребят из Одноклассников:


    Итог

    На данный момент пул является неотъемлемой частью нашей системы. Вокруг него появились новые скрипты и новые методы. Благодаря гибкости и простоте систему удобно развивать и контролировать.

    Немного о том, что получилось в итоге:

    • Удобный инструмент для ручного и автоматизированного взаимодействия Badoo с Facebook;
    • Более 20 уникальных тестов, использующих пул facebook-аккаунтов: регистрация/авторизация, верификация, загрузка фотографий с FB-аккаунта, поиск друзей на Badoo, шаринг наград и так далее;
    • В пуле 9 различных приложений, использующих в общей сложности примерно 1.5к активных пользователей;
    • QaApi-методы умеют создавать FB-аккаунты, делать их друзьями, заливать им фотографию, ассоциировать FB-аккаунты с нашими тестовыми пользователями;
    • Система сама поддерживает необходимое количество FB-аккаунтов и чаще всего не требует никакого ручного вмешательства.


    За более чем год использования api работал стабильно. Всего раз возникла проблема с токенами пользователей, но разработчики facebook пофиксили ее довольно быстро. Кому интересно подробнее — developers.facebook.com/bugs/1662068220677444.

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

    Спасибо за внимание!

    Виталий Котов, QA-инженер по автоматизации.
    Badoo
    438.08
    Big Dating
    Share post

    Similar posts

    Comments 22

      +1
      Шоты работают прям с живой базой данных? Или все же слепок с нее?
        +2
        Да, шоты работают на живой базе.
        Суть тестирования на шоте — проверка работоспособности задачи в боевом окружении. Слепок боевой базы в проекте наших масштабов огромен, это работа не одного сервера.
        Если же взять только кусок базы, то проверка почти не будет отличатся от проверки на девеле.
          +1
          такой подход, конечно, привлекателен, но я чет не решился бы тесты гонять на боевой базе
            +2
            Ваши опасения понятны. Но в данном случае суть в том, что все пользователи, которые участвуют в тестах, тестовые. И QaApi может работать только с ними. Это все служит надежной защитой «от дурака».
              0
              Интересно узнать как вы разделяете тестовые данные от обычных и как реализовано ограничение прав доступа QaApi. Автоматизированные тесты запускаемые на реальной базе довольно привлекательны в некотором смысле, но количество тонкостей немного пугает.
              0
              Тогда смысл шотов пропадал бы.
                –2
                А если сделать дамп боевой базы и развернуть её на тестовом сервере. Мы в компании так всегда делаем. Если конечно в этом есть потребность.
                  0
                  я так понимаю, там огромная база, которую просто так не сдампаешь в разумные сроки
                    0
                    Вы реально представляете дамп базы Баду? Это далеко не один сервер… Это нехилая такая ферма…
                      –1
                      Я не спорю, но а если к примеру специально для тестирования развернуть и 1 раз в пару недель обновлять её? Пусть даже во время тестирования будет не самая свежая версия, но даже в пару недель будет уже неплохо. А по поводу серверов, то думаю у такого монстра как Баду есть парочку свободных ну или арендовать в дата центре? (я не знаком с их внутренней структурой, поэтому это только предположения и вопрос к более опытным людям) ^_^
                        0
                        Еще раз задам вопрос — вы размеры кластера представляете? Получается что просто так держать такую ферму — это просто дико не выгодно по деньгам. Чисто экономически. Ну это как гуглу сказать — так вы бэкап своего индекса сделаейте и на нем эксперементируйте новые логики построения индекса вместо того чтобы на живой базе :).
                          0

                          Скорее всего, у гугла есть девелоперская копия индекса.

                            0
                            И у ФСБ и ЦРУ тоже. Попробуйте еще раз объем представить :).
                          0
                          Давайте я расскажу чуть подробнее. Badoo — это не несколько баз данных в mysql. Badoo — это два (почти три) полноценных датацентра. Это довольно сложная система репликации и шардинга. Плюс фото и мемкешы, система переводов, различные демоны и так далее. И все это дело каждый день улучшается, меняется, ломается и чинится. Бегут какие-то альтеры, какие-то селекты, тестовые инстансы демонов и АБ-тесты. Одним словом — разрабатывается.

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

                          Такие дела.
                            0
                            Наши базы данных крутятся примерно на 300 серверах, причём это только пользовательские данные. Они конечно дампятся раз в какое-то время, но даже просто развернуть такой дамп (при условии, что вы уговорили начальство купить ещё 300 лишних серверов) будет требовать несколько суток.
                  0
                  А действительно ли вам нужны полноценные интеграционные тесты с facebook'ом, не рассматривали ли вы возможность замены facebook'а на соответствующий mock?
                    0
                    Mock не поможет если API FB изменится и что-то сломается.
                      0
                      Да, если измениться FB API, полноценные тесты это конечно зафиксируют, но если такая ситуация действительно случится, то о том что что-то сломалось вы скорее узнаете не из тестов, а из массовых ошибок аутентификации/регистрации на проде=)
                      Ну и кроме того, API никогда не должен изменяться. Как правило при доработках API выпускается его новая версия, которая работает параллельно текущей версии, а не заменяет ее. Ну а так как это все таки FB, то отвалившийся API это что-то крайне редкое и странное. Ну и добивает всю эту ситуацию то, что даже если вы обнаружили данную проблему с помощью тестов, то вы вряд ли сможете с этим что-то сделать, ну если только в техническую поддержку FB'ука написать…
                        0
                        Используя mock не будем ли мы тестировать тестовую логику?

                        Методы, которые формируют запросы к сторонним сервисам, довольно сложные в плане зависимостей и количества условий. Если там что-то сломается, а мы замокаем ответ от FB, мы не поймаем проблему на стейджинге.

                        А ловить отказ одного из основных способов регистрации/авторизации на продакшене по графикам того, сколько реальных пользователей не смогло попасть на сайт — попахивает письмом с заголовком «WTF??» всем нам на рабочую почту. :)
                          0
                          > Используя mock не будем ли мы тестировать тестовую логику?
                          К сожалению, с mock'ами всегда имеется такая проблема=/ Мне вообще всегда довольно сложно дается ответ на вопрос использовать их или нет. Обычно для этого я задаю себе вопрос: «а что конкретно я тут тестирую??» и тогда решение дается проще. Если в вашем случае запросы к сервисам действительно имеют кучу параметров, то ваш текущий способ конечно же полностью оправдан.
                          Но все же, в случае регистрации/аутентификации через FB, параметров должно быть минимум. Я правда никогда не работал с API FB, и вероятно сильно ошибаюсь, но для меня эта ситуация кажется странной.
                          0
                          Вот пример: вы сделали некий функционал который использует 50% API фейсбука. Написали тесты, всё окей. Выкатили в продакшин… через неделю добавили новых функций по старым мокам (моками покрыли старую версию всю целиком), написали тесты, тесты прошли, выкатили в продакшин — новая часть функционала не сработала — появились жалобы.
                            0
                            > вы сделали некий функционал который использует 50% API фейсбука
                            ИМХО, в таком случае уже появляется другая проблема — selenium для таких целей не очень подходит.
                            Фактически мы проверяем что сторонний API работает так как мы ожидаем. В этом конечно нет ничего плохого, но в данном случае лично я бы проверял именно ответы API, а не работу системы с данным API.
                            PS: Я просто пытаюсь рассуждать, не сочтите что я с вами спорю.

                    Only users with full accounts can post comments. Log in, please.