![](https://habrastorage.org/getpro/habr/upload_files/0ba/51d/0b7/0ba51d0b76a1639930b9814ed9154dd8.png)
Многие фичи приложения невозможно быстро протестировать, не меняя исходный код. Представьте типичную задачу, с которой может столкнуться каждый разработчик: через три дня после регистрации пользователю нужно предложить купить премиум-доступ к продукту со скидкой. Чтобы проверить, работает ли это промо, нужно зарегистрировать тестового пользователя и подождать три дня до появления заветного окошка.
Очевидно, что разработчик не будет столько ждать. Он просто сменит в коде значение константы, которая задаёт временной интервал, с трёх дней на 20 секунд — и получит результат почти мгновенно.
Допустим, данные для промопредложения отдаёт сервер, а отрисовывается оно на клиенте. Если серверный тестировщик работает в среде, которая допускает манипуляции с кодом, он тоже быстро справится с задачей. Но как только она окажется там, где возможность менять код отсутствует (стейджинг, продакшен), возникнет проблема.
Разумеется, для воспроизведения кейса менять значение прямо на стейджинге или продакшене невозможно. Можно было бы решить эту проблему, переместив значение в базу, но и в таком случае возникли бы трудности:
существенно усложнился бы код;
пришлось бы давать права на update базы всем заинтересованным лицам (и следить за этим), а также увеличилась бы вероятность человеческой ошибки при работе с базой, что может иметь самые разные последствия;
значение в базе одно для всех пользователей: оно не может быть изменено для конкретного сотрудника, оставаясь прежним для остальных.
Эта история не закончится с выходом серверной задачи в продакшен. Ни клиентские разработчики, ни тесты, имитирующие поведение пользователя, например Calabash или Selenium, тоже не имеют возможности изменять серверный код.
Мы не можем позволить себе постоянно тратить время, силы и ресурсы на решение подобных проблем при воспроизведении новой функциональности. Поэтому мы начали искать способ влиять на параметры системы, не меняя исходный код. Этот способ должен быть:
простым для пользователя: его будут использовать все инженеры вне зависимости от специализации;
доступен для тестов различных типов: Calabash, Selenium, функциональных тестов;
простым для разработчика: реализация фичи не должна становиться дороже из-за внедрения возможности влиять на её параметры;
безопасным: как бы этот способ ни работал, это не должно повлиять на реальных пользователей на продакшене;
легкодокументируемым.
В Badoo такой инструмент называется QAAPI. По названию можно понять, что изначально он создавался для помощи тестировщикам, но оказался настолько мощным и многогранным, что сегодня без него не может представить свою работу ни один сотрудник, участвующий в процессах создания новых и поддержки существующих фич.
В этой статье я расскажу о концепции QAAPI и о том, как она реализована в Badoo.
Использование QAAPI
QAAPI представляет собой набор вызываемых по HTTP и возвращающих JSON-ответ методов. Такой формат подходит всем: человек может вызывать методы из браузера, в то время как в каждой разновидности тестов (Calabash, Selenium и пр.) найдётся способ сделать HTTP-запрос. Аналогично и с JSON-ответом: он одинаково легко читается как человеком, так и тестами.
Для пользователя QAAPI решение проблемы с показом промо после регистрации выглядело бы так: есть метод SetPromoTimeOffset и соответствующий URL, принимающий в качестве GET-параметра количество секунд, по прошествии которого с момента регистрации необходимо показать промо, а также ID пользователя, для которого будет использоваться новое значение. К примеру:
/SetPromoTimeOffset?seconds=20&userid=12345
Запрос возвращает лаконичный ответ:
{ “success” : true }
И спустя 20 секунд после регистрации пользователю с ID 12345 показывается промо.
Как же реализовать такой метод?
Создание QAAPI-метода
Каждый QAAPI-метод включает в себя три составляющие:
описание;
входные параметры;
тело метода с логикой.
Все параметры QAAPI строго типизированы и описываются отдельными классами с собственной валидацией. Они могут быть простыми, как Boolean или DateTime, и специфическими, как, например, user_id или session_id.
Класс метода SetPromoTimeOffset
выглядел бы следующим образом:
class SetPromoTimeOffset extends \QAAPI\Methods\AbstractMethod
{
public function getDescription() : string
{
return <<<Description
Sets a time offset in seconds between the user's registration date and the promo's showing
Description;
}
public function getParamsConfig() : array
{
return [
'user_id' => \QAAPI\Params\UserId::create(),
'seconds' => \QAAPI\Params\PositiveInteger::create()->setDescription('Offset in seconds'),
];
}
public function run() : \QAAPI\Models\Output
{
// logic here
return \QAAPI\Models\Output::success();
}
}
Принцип работы метода зависит от его назначения. Подавляющую часть методов можно отнести к одной из трёх категорий:
получение данных;
изменение данных;
изменение логики сервера.
Первые две категории подразумевают простое взаимодействие с базой. Для изменения логики сервера необходимо как-то пометить нужного пользователя и сохранить для него необходимые значения.
Безопасность QAAPI
Безопасность QAAPI реализована на трёх уровнях. Первый — полный контроль разработчиков над тем, что делает метод, и скрытие реализации от конечного пользователя. Нет необходимости давать кому-либо права на базу и следить за этим. Сама система QAAPI требует авторизации, которая у нас реализована при помощи Google-авторизации для инженеров и секретного токена в хедере для тестов.
Второй уровень безопасности — это сетевое ограничение доступа к QAAPI: им можно пользоваться либо из офиса, либо при помощи VPN.
И третий уровень — принципиальное решение, позволяющее QAAPI работать исключительно с пользователями, помеченными как тестовые. Это избавляет нас от рисков что-то сломать для реальных юзеров, а также нарушить какие-то правила работы с персональными данными, к примеру GDPR.
Документация
Количество методов в нашей системе уже превысило 1500. Разумеется, удержать их в голове невозможно, поэтому нужно было позаботиться о создании подробной документации с опцией поиска и детальными описаниями. Строгое описание каждого метода позволяет генерировать такую документацию на лету.
Вот так выглядит наш новый метод:
Таким же образом мы легко можем генерировать и классы-клиенты для всевозможных тестов (Calabash, Selenium и пр.).
QAAPI в Badoo и Bumble
Области применения QAAPI, как показывает наш опыт, ограничиваются лишь креативностью разработчика. Его можно использовать в различных ситуациях:
— для регистрации тестового пользователя, когда нам нужно задать определенные пол, возраст, увлечения, количество и тип фотографий;
— для обмена сообщений между пользователями: создаём второго юзера с нужными параметрами и отправляем сообщение от его имени;
— при активации сервисов, воспроизведения флоу верификации пользователя, оплаты и так далее.
Методы можно комбинировать, вызывая один из тела другого. Это не делает вызов более дорогим: внутренние взаимодействия методов осуществляются локально, а не по HTTP.
Также было бы большим упущением, если бы часть нашей команды, которая не использует PHP, была лишена всей выразительности QAAPI и вынуждена довольствоваться только готовыми методами. Для неё мы создали вспомогательный инструмент, позволяющий писать сценарии на Lua и вызывать в них QAAPI-методы в любых сочетаниях.
В отличие от методов сценарии не лежат в репозитории, поэтому ими также пользуются разработчики, чтобы не создавать лишние методы и иметь возможность изменять их на лету. Сценарий может также являться своеобразной документацией по воспроизведению той или иной фичи и передаваться по всему флоу проекта от серверного разработчика до клиентского тестировщика-автоматизатора.
Заключение
Концепция QAAPI очень проста в реализации. Её можно использовать в любом проекте, где необходимо воспроизводить сложные кейсы и покрывать их тестами.
Нам QAAPI даёт массу преимуществ:
подготавливает данные для автоматического и ручного тестирования;
обеспечивает быстрое и безопасное получение данных о состоянии пользователя/фичи;
становится точкой входа для изучения работы функциональности (например, если метод включает какой-нибудь сервис, из тела метода легко перейти в код самого сервиса);
сценарии фактически являются документацией фич со сложным флоу.
Создание простого метода обычно не занимает больше пары минут, при этом QAAPI помогает сэкономить колоссальное количество времени. Помимо очевидных преимуществ, правильно написанный метод или сценарий позволяет абстрагироваться от деталей фичи и сфокусироваться на решении задачи.
QAAPI используется в Badoo с 2013 года, и сегодня представить нашу жизнь без него практически невозможно. При этом поддержка инструмента нам практически ничего не стоит: документация и классы-клиенты для тестов генерируются автоматически, каждый метод самостоятелен и не зависит от других.
Мы часто упоминаем QAAPI, но ещё ни разу не рассказывали о нём подробнее в статьях. Надеемся, этот рассказ вдохновит вас создать подобный инструмент или поделиться с сообществом другими своими необычными решениями.