Тестирование VK API при помощи VK Java SDK
На митапе VK Tech Talks | QA, прошедшем 9 сентября, инженер по автоматизации тестирования Михаил Кузнецов выступил с докладом «Тестирование VK API при помощи VK Java SDK». Представляем расшифровку выступления.
Несколько слов о VK API
Существует несколько версий VK API, с которыми можно работать, и два типа токенов: групповые и пользовательские. Также существуют сервис-токены, но в тему доклада они не вошли. В API имеется больше 40 разделов с более чем 400 методами, которые разделяются на приватные и публичные. VK API работает напрямую с JSON-схемой.
JSON-схема
JSON-схема — это некоторый стандарт описания JSON-объектов. Посредством ключевых слов она валидируется и проверяется на актуальность ожидаемого.
В качестве примера возьмём простой JSON с тремя полями: id, first_name и last_name. Чтобы описать поля, нужно написать такой JSON:
Каждое поле находится в секции properties, содержит информацию о своём типе и описание. Мы можем указать поля required, которые обязательно должны присутствовать в JSON-объекте, иначе это будет невалидная схема. Настройка additionalProperties говорит, что в этом JSON не может быть больше полей, чем представлено.
Как JSON-схема генерируется в VK?
Сначала разработчики пишут код. Прописывают бэковые ручки, ответы, модель ответов, после чего сложными манипуляциями код преобразуется в JSON. В итоге мы получаем большую JSON-схему, которая описывает методы, ответы и запросы.
Как будет выглядеть метод API в рамках схемы?
У метода есть поля name, description, acces_token_type (это типы токенов, с которыми может быть вызван этот метод). Будут указаны параметры, чтобы вызвать запрос, и помечены параметры обязательные и необязательные. Могут быть и другие настройки: responses, который указывает реферальной ссылкой на JSON-объект к JSON-схеме и встраивается туда.
Ошибки
Ошибки конкретно этого метода:
Ответы выглядит намного проще:
Здесь есть название этого объекта и ссылка на то, что он вернёт. Бывают простые объекты и более сложные — они являются объектом, но могут содержать внутри такие поля, как array. Например, если мы хотим получить архив историй, то мы получим объект, у которого будет в модели response, properties, count (количество архивных историй) и items (сами истории). Они могут быть и объектом, и не объектом.
Возвращаемый объект выглядит так:
Он большой, содержит тип, properties (это поля), поля required и additionalProperties (эту настройку вы видели на одном из первых слайдов).
Как генерируется документация VK API?
Документация генерируется на основе схемы. Это упрощает генерацию странички, которую вы видите в документации API. Например, у есть группы, такие как «Авторизация». В группах есть список методов, их описание и аннотация к группам. К группе «Авторизация» относится метод checkPhone. Он отображается в документации на своей страничке с параметрами, результатом и кодами ошибок. На последнем слайде в «карусели» есть пример того, как параметры запроса описаны в схеме и в документации. К сожалению, это старый скриншот, поэтому описание сделано вручную. Сейчас всё генерируется автоматически.



Java SDK
Java SDK — это набор готовых реализаций для работы с API VK. Для «ВКонтакте» существует шесть SDK, но здесь поговорим только о Java.
Как она генерируется?
У нас есть JSON-схема, в которой описаны все запросы, ответы, модели возвращаемых объектов. Потом эта схема парсится и превращается в Java-код, который представляет модели ответов, запросов и возвращаемых объектов. Он «прикручивается» к существующему коду, написанному вручную.
Типы пользователей
Существует три типа пользовательских токенов, но мы поговорим только о двух, потому что третий в наших автотестах пока не используется. Это UserActor и GroupActor. Я буду говорить о них в контексте Java SDK. Это интерпретация связки токенов пользователей и его ID, необходимого для передачи параметра AccesKey. Они экстендятся от объекта Actor.
Как выглядит запрос Java SDK?
Все запросы описаны как некоторые Query, которые наследуются от абстрактного Rebuilder, которые в свою очередь наследуются от абстрактного класса APIRequest. Каждый класс Query генерируется на основе схемы и превращается в то, что вы видите справа на слайде.
Параметры
Чтобы параметризовать Query, мы можем пойти двумя путями:
- Подход в виде билдеров, где мы указываем Query. В данном случае это create album. Параметризуем его методами title, description и comments_disabled. Это метод создания альбома. Title — название, description — описание, и третий параметр — доступность комментирования. Далее вызывается метод execute, который реализован уже непосредственно в классе pre request.
- Во втором методе мы можем использовать встроенный на уровень AbstractQuery метода SafeParam. Он переопределён для разных типов данных и мы можем задать параметр Query, где .unsafeParam принимает в качестве первого аргумента и вторым аргументом значение параметра. Всё это переопределено в классах AbstractPreBuilder для разных типов.
Запрос Java SDK
Если мы «провалимся» в метод execute, который вызывается для выполнения запроса из Query, то увидим, что запрос уже выполняется на уровне HTTP, после чего реализуется в JSON-объект и проверяется на наличие поля error, которое скажет нам об ошибке от API, либо response, которое скажет, что ошибки нет.
Для серверизации внутри используется GSON (библиотека Google). После этого объект возвращается, и мы уже можем с ним работать.
Модель Java SDK
Модель Java SDK — самая простая SDK-модель, созданная на основе схемы и содержащая в себе поля обязательные и необязательные. Обязательность регулируется аннотацией Required (GSON-аннотация). У нас тут есть геттеры, сеттеры, переопределённые методы и String prettifier.
Тестирование Java SDK
Java SDK работает с ошибками как с Exceptions: если внутри executor JSON-объект, то снаружи этот JSON-объект будет либо валидным, либо Exception. Другими словами, метод Execute создаст исключение в том случае, если API вернёт нам “error”. Поэтому в рамках разработки это отличное решение, но тестирование осложняется.
Как мы решили эту сложность?
Приведу пример Exception, бросаемого из SDK. Здесь написано, что есть параметр title, у которого минимальная длина обозначена как 2 символа. Мы напишем код, который будет вызывать QueryCreateAlbum с параметром title длиной 1 символ — символ “x”. На выходе получаем exception, где будет указано API Exception Error. Он расскажет нам о появившихся проблемах и предоставит код ошибки.
Это наш типичный тест. Мы придерживаемся концепции «Три “А”» (Arrange App Assert). Здесь всё разделено на логические блоки:
- инициализация пользователя, с которого мы будем выполнять запрос;
- execution, то есть здесь мы выполняем запрос.
Поскольку мы не хотим писать много лишнего кода, самым оптимальным вариантам является параметризация и работа через подход DDT (Data Driven Testing), что ложится очень красиво на концепцию TestNG. Также у нас есть обработка ожидаемых исключений. Как известно, DDT предполагает как позитивные, так и негативные кейсы. Поэтому в случае негативных кейсов мы должны как-то обрабатывать исключения, которые появляются в методе Execute. Так у нас появился блок Assert, где реализованы специальные самодельные компараторы. Для Assert используется AssertJ, потому что это просто удобно.
Организация автотестов
Мы написали ActorProvider — это класс, который раздаёт пользователей в рамках нескольких потоков. Каждый тест приходит к ActorProvider и берёт пользователя. Но количество пользователей ограничено. Поэтому, если пользователя нет, тест встаёт в очередь на ожидание свободного.
Как это работает изнутри?
ActorProvider активируется по всем нашим токенам и делит их на функциональные группы. Когда у нас есть готовые пользователи, в рамках тестов мы используем их параллели. После завершения каждого теста пользователи освобождаются и тесты снова могут их взять. Внутри ActorProvider реализован BlockingQueue (очередь с N количеством пользователей). Когда пользователи кончаются, тесты встают в очередь на получение новых. Объекты пользователей реализуют интерфейс AutoClosable, что позволяет нам условно интерпретировать эти объекта как ресурсы и возвращать их после окончания блока try, используя в тестах конструкцию try-with-resources.
В ActorProvider существует две очереди: для групповых и пользовательских токенов. Чтобы можно было работать с очередью, UserActor и GroupActor были обёрнуты в специальные объекты: PoolUserActor и GroupUserActor. Они наследуются, что обязывает их выполнить метод Close в конце своей работы, тем самым вернувшись в pool.
Следующий блок — Act. Здесь тоже реализован кастомный executor запросов. Метод performRequest принимает на вход разного рода Query и Test Data в качестве второго аргумента. TestData у нас предоставляется через сайт провайдера.
Как это выглядит внутри?
Существует два метода, один из которых предопределённый:
- выполнить запрос без параметров;
- выполнить запрос с параметрами.
В качестве параметра принимается объект Request_Data. Наши методы натированы Allur-аннотациями, что позволяет нам генерировать репорты. В AllurReport передаются параметры запросов, которые были использованы, и то, что мы получили обратно Response. Также здесь у нас реализована обработка ожидаемых исключений.
Внутри метода CompareException происходит сравнение фактического exception с ожидаемым. Если они совпадают, значит исключение было ожидаемым и тест пройден. Если нет, мы получаем ошибку exception на уровень выше и тест краснеет.
Data driven
Здесь существуют DataProvider, которые реализуются для каждой из групп. В свою очередь они наследуются от такого класса, как BaseDataProvider. У нас существуют наборы данных, которых может быть произвольное количество. Есть метод Initialize, реализованный в классе BaseDataProvider, поэтому можно удобно всем этим пользоваться.
Как мы храним тестовые данные?


Тестовые данные мы тоже храним в виде JSON, где каждый набор — это request. Другими словами, у нас существует массив запросов в количестве, необходимом для каждого quest’а. Каждый запрос содержит имя, эквивалентное методу API, который описан в спецификации. В блоке параметров есть два параметра и ожидаемый результат. Вместо такого поля может быть ExpectedException, куда мы передаём ожидаемые исключения. Вот пример ещё одного набора тестовых данных эквивалентных предыдущим, но с той разницей, что здесь уже три параметра. Таким образом мы можем не написав ни одной строчки кода запустить новый тест. Также здесь есть ExpectedResponse — это будет уже другой объект.
Блок Assert
Нашим компаратором реализована логика сравнения двух строковых объектов типа object или списка объектов. Метод CompareObjects переопределён для сравнения со строкой двух объектов. Ещё у нас есть метод для сравнения списка объектов. Благодаря этим методам мы можем игнорировать поля, которые нам не интересны, до любого уровня вложенности.
Представим, что у нас есть ожидаемый JSON и фактический. Но в виду того, что в некоторых JSON существуют поля, которые динамически меняются, например дата добавления или ID, мы не можем их сравнить один к одному, потому что в этом случае получим ошибку. Исключая эти поля, мы игнорируем их в сравнении. Сравнение происходит таким образом, что каждый объект интерпретируется как мапа вложенных мап до уровня вложенности, эквивалентного уровню JSON, и рекурсивно сравнивается. Также у нас реализован метод CompareExceptions, чтобы сравнивать фактические и ожидаемые исключения.
Вот как выглядит блок, когда мы сравниваем два объекта, которые не соответствуют друг другу. Здесь ожидается, что объект, который мы получили, содержит поля description, privacy_comment, privacy_view, size, thumb_id и title. Но по факту, к сожалению, он содержит пустое поле description, и мы получаем ошибку. Таким образом исключение выводится на такой красивый лог.
Заключение
В завершение доклада хочу сказать, для чего мы использовали SDK:
- Модели описания возвращаемых объектов реализованы, что избавляет нас от рутины.
- Объекты в JSON-схеме провалидированы уже на этапе создания.
- API-методы уже реализованы, и нам остаётся только немного прикрутить всё так, как нужно нам, и сконфигурировать.
Полную запись выступления Михаила можно посмотреть здесь:
The Brown Room — независимое интернет-издание про социальные сети и современные технологии
Автор: Влад Воробьёв
Корректоры: Лена NL, Арсений Метелев
Слайды и данные: VK Tech
