Ретроспективные уроки автоматизации: тестирование API |
12.07.2019 00:00 | ||
Автор: Виктор Славчев (Viktor Slavchev) Это последняя часть моего цикла статей о ретроспективных уроках автоматизации. Мне кажется, я достаточно выразил свою философию тестирования и личный опыт. Последнее, чем я хочу поделиться, относится к проекту, с которым я работаю уже год, и касается создания автоматизированных проверок API бэкэнда, который мы сейчас разрабатываем. Мы пишем тесты на PHP во фреймворке Codeception. Я не буду углубляться в особенности фреймворка – я сфокусируюсь на базовых вещах. Итак, вот они – уроки по тестированию API, которые мне нелишним было бы знать заранее – до того, как я изрядно налажал. Недостаток информации Первое, что я хочу отметить – это вопиющая нехватка качественных материалов по тестированию API. Безусловно, когда я приступал к тестам API, я знал, что такое API и для чего оно нужно, но мне нужна была информация о принципах API-тестирования. API – та область, где имеет смысл инвестировать в автоматизацию, потому что это интерфейс, которым пользуется код или приложение. Следовательно, он идеально подходит под определение приложения, которое можно легко тестировать через код. Меж тем я был крайне удивлен, что информация об основах тестирования API так ограничена. Когда я только начал работать с ним, я уже пять лет работал тестировщиком и умел тестировать приложения, но мне все равно пришлось побиться головой о стену в поисках ответа на ряд вопросов:
Некоторые из этих вопросов так и остались без ответа, а на некоторые я нашел ответ самостоятельно, путем проб и ошибок. Итак, я практически не нашел полезной информации о тестировании API. В основном это были слайды с конференций и короткие статейки. Если вы знакомы с API-тестированием и имели с этим дело, я прошу вас, напишите об этом книгу, это будет очень полезным делом. Вот несколько полезных материалов для тех, кто начинает тестировать API или хочет узнать об этом больше: Exploring your APIs with Postman by Amber Race (слайды) – не видел доклада, но слайды с виду довольно полезные. Service virtualization by Bas Dijkstra (бесплатная книга) – Баз всегда был моим героем во всем, что касается автоматизации и тестирования API Статья от Smart Bear – полезно и интересно, особенно описание трех уровней тестирования API. Automating and Testing a REST API – за авторством злобного тестировщика Алана Ричардсона, очень полезный практический материал. Особенно мне понравилась идея приложения как API и API как приложения. Помимо вышеупомянутых статей, есть множество курсов и воркшопов по тестированию API. Однако они зачастую чересчур концентрируются на основах (что такое API, что значат коды статуса, и т. п.), и не уделяют достаточно внимания целям тестирования и стратегиям, позволяющим достичь этих целей. Что вы тестируете, тестируя API?Проект, над которым я работаю – REST API, использующийся SPA-приложением, написанным на React. Я подключился к проекту на ранних стадиях, когда интерфейса и самого приложения еще не существовало, и это было интересной и сложной задачей. Итак, как же, черт побери, тестируется этот API? Я намекну – когда интерфейса еще нет, вы почти ничего не понимаете в том, как сервисы вызываются и используются. Вот что я мог сделать в плане тестирования:
Все это очень мне помогло, и я вынес из этого опыта несколько ценных уроков:
Это казалось мне хорошей идеей, но работает это только с простенькими конечными точками. При сложной и глубокой бизнес-логике изолированно тестировать конечные точки очень сложно. Для полноты тестирования API вам нужно понимание, как они используются в клиенте.
В норме документация, генерируемая автоматически, никак не помогает разобраться в сложной логике, и в случаях, когда данные на входе могут варьироваться или имеют ограничения, она чуть более чем бесполезна. В любом случае имеет смысл использовать ее как явный оракул с подходом "если бы я пользовался этим API впервые, какую информацию эта документация может мне дать?". Это поможет вам найти проблемы в API и в самой документации.
Это то, с чем большинство тестировщиков не может разобраться. Между исследованием и записью тестов нужен баланс. Создавая автоматизированные проверки, мы должны осознавать, что результат – это всего лишь формализованная версия тестирования, проведенного до этого. Путешествие важнее точки назначения, и исследование важнее, чем формализованные скрипты, которые станут его результатом. По моему опыту то, что я делаю, исследуя API, дает мне куда больше информации о проблемах, чем тесты сами по себе. С другой стороны, тесты – это формальная версия этих знаний, и я могу использовать их снова и снова, чтобы убедиться, что ничего не изменилось. Если что-то изменится, я снова приступлю к исследованию. Я буду подробнее говорить об этом в цикле статей "Ретроспективные уроки исследовательского тестирования". Важные когнитивные барьерыЕще один интересный факт, с которым я столкнулся, тестируя API: мне было очень трудно разобраться, какие данные (валидные, невалидные, null, пустые строки…) использовать в качестве параметров для наших сервисов. Пример: одна из конечных точек, относящихся к логину, выдавала ошибку 500 при использовании китайских иероглифов на входе. Я тестировал ее через API, и мне не пришло в голову попробовать использовать иероглифы, хотя тестируй я через интерфейс, я бы обязательно это сделал. Вот что нужно из этого вынести: все мы люди, и для качественного тестирования нам нужен интерфейс, ориентированный на человека. Наше понимание ограничено, наше восприятие и мышление подвержены искажениям, мы легко вляпываемся в собственные ловушки разума. Если вы хотите как следует протестировать ваш API, убедитесь, что вы знаете:
Мне кажется, это пригодится абсолютно всем. Типы тестовПробуя различные подходы, я обнаружил, что тесты, имеющие смысл, можно разделить на три группы. Что мы хотим знать об API в плане тестирования?
Исходя из этих задач, я придумал следующие типы тестов: Проверки кодов статусаЦель этих проверок – просто убедиться в функционировании конечной точки. К примеру, ваша спецификация гласит, что у вас будут такие коды: 200 – успешно 400 – неверные данные 404 – недоступный ресурс, и т. д. Попробуйте создать простенькие тесты и убедиться, что каждый из этих кодов можно получить в ответе. Цель: Это проверки-ловушки, они убедятся, что ничего не сломалось, когда в продукт вносятся изменения, и сразу же просигнализируют, что что-то ведет себя не как всегда. Они должны быть простыми, быстрыми и однозначными. Двусмысленность тут недопустимо. Несколько советов:
Структурные проверкиКоды статуса – это здорово, но они просто сообщают, работает ли сервис так, как гласят формальные правила его работы. Клиенту важны данные, а код 200 или 400 ничего про данные не говорит. К тому же проверка кодов статуса для GET-методов вообще практически ничего нам не сообщает. Я решил, что полезно будет протестировать, что возвращаются правильные данные. Для этого мы использовали встроенный в Codeception метод seeResponseMatchesJsonType. Он смотрит в ваш json-ответ, используя json-path (похоже на XPath, но используется для json) и проводит валидацию того, что определенная переменная вашего ответа содержит данные типа Х. Вот пример с сайта Codeception: PHP
Точно так же вы можете сравнивать любые типы переменных, от массивов до плавающей точки. Когда дело доходит до сравнения значений и паттернов, можно сделать вот что:
Цель: Может быть полезным для валидации данных, возвращаемых GET-сервисами, так как они зачастую содержат большое количество информации. Главный плюс таких проверок для меня в том, что они предупредят, если данные не возвращены. К примеру, вы делаете post-запрос к конечной точке Х и получаете ответ с ID записи в базе данных. Отсутствие этого ID сигнализирует о серьезных проблемах. Несколько советов:
Проверки сценариевЯ вдохновлялся идеей Алана Ричардсона о приложении как API. Тесты, вызывающие несколько разных конечных точек так, как это делало бы приложение, нужны для полноты понимания API и его использования. Цель: Вы можете возразить "но зачем мне это делать, фронт-энд все равно сделает это". Мы делаем это в основном для того, чтобы найти расхождения между дизайном сценариев на фронте и данными, которые получаются с бэкэнда. Это сбережет немало времени разработчикам вашего фронтэнда. Основная идея – разработать простые сценарии. Например, вы открываете пользовательский профиль и обновляете его. В качестве теста вы используете GET-запрос, получаете данные и отправляете их как POST. Несколько советов:
Дизайн фреймворкаОб это я бился довольно мучительно. Я пытался найти альтернативу шаблонам для API-тестов, но так их и не нашел. В результате я разработал собственный дизайн для фреймворка, который удовлетворяет нашим нуждам. Вот чем я руководствовался:
Это часто используется в шаблонах для UI-тестов вроде Page Object. Пишите фреймворк так, чтобы ваши тесты использовали абстракции уровнем выше, чем встроенные в инструмент функции.
Если у вас есть действие, которое регулярно выполняется в тестах, имеет смысл сделать его частным методом тест-класса или базового класса, чтобы облегчить повторное использование кода и минимизировать ошибки от копипасты.
В этом случае мне повезло – я заручился поддержкой разработчиков, которые помогли создать инструменты для генерации данных и записей в БД, которые могли понадобиться при тестировании API. Важный урок – сотрудничайте со своими разработчиками, они могут серьезно улучшить вашу работу множеством способов помимо исправления багов. Пример: если я собираюсь тестировать WordPress API, мне понадобится инструмент, генерирующий посты, или пользователь с админскими правами.
В процессе разработки фреймворка вы узнаете о множестве вещей, которые можно сделать лучше, эффективнее, с переиспользованием кода. С этим вам помогут такие концепции ООП, как полиморфизм и наследование. К примеру, у нас была логика, которую мы повторяли в наших методах настройки. Я решил создать цепочку наследования, чтобы тест-класс использовал только ту часть, которая ему необходима, и ее не надо было копировать и вставлять в сто разных мест. Если у вас есть возможность провести рефакторинг фреймворка – сделайте это, не откладывайте это на потом. Это может показаться чрезмерной тратой времени, но это оправданная трата – вы вкладываетесь в улучшенную поддержку тестов, более высокую скорость, повышенную надежность. Будет ошибкой пытаться создать идеальный фреймворк с первого раза. Возможно, если вы занимаетесь этим лет двадцать, это реализуемо, но по моему опыту, создание кода – органичный процесс, у него есть жизненный цикл и естественная эволюция. Если вы насильно ускорите эволюцию, то породите мутанта. Я это еще не делал, но это может пригодиться
Вот краткий список уроков, которые я извлек из тестирования API за то недолгое время, что я этим занимаюсь. Я не считаю себя экспертом, поэтому поправьте меня или дополните, я буду рад! |