У Bas Dijkstra новый пост про тестирование API: Как вы проверяете большие ответы в своих API-тестах?
В прошлый раз мы обсуждали стратегию тестирования API, почитать можно по ссылке.
Теперь давайте разбираться как проверять ответы если у вас Java, у меня есть что дополнить по этой теме!
Список подходов по мнению Баса:
🔍 Approval testing (сравнение с эталоном)
Если у вас есть заранее известный корректный ожидаемый ответ, можно сравнивать его с фактическим целиком, вместо проверки каждого отдельного элемента.
❗️Минусы: придётся как-то обрабатывать изменяющиеся поля (уникальные ID, поля с датой и т.д.). Также, если ответ содержит списки, то такая проверка может ломаться при изменении порядка элементов в списке, даже если их содержимое не менялось.
💡Мое дополнение: применял данный подход на самом старте API автоматизации, хранил expectedResponses в отдельной папке и использовал библиотеку JSONAssert, которая позволяет исключить сравнение по какому-то полю через CustomComparator (StackOverflow). Также есть режим JSONCompareMode.LENIENT, позволяющий игнорировать порядок полей и лишние поля (например, Id, даты и прочее можно не добавлять в expected json). Минус: не проверите контракт этих полей и не среагируете на новые поля.
📉 Сокращение объёма ответа
Если ответ содержит длинные списки с десятками или сотнями элементов, можно попытаться изменить тестовые данные так, чтобы возвращалось, например, всего 3 элемента.
❗️Минусы: зависит от того, насколько у вас есть контроль над данными. Кроме того, при таком подходе можно пропустить некоторые баги, которые проявляются только при большом количестве элементов.
💡 Мое дополнение: тут особо добавить нечего, все так. Обычно в пре-реквизитах и пост-шагах создаем тестовые данные, очищаем предыдущие, чтобы в самих тестах не было ничего лишнего в ответах.
📦 Десериализация
Преобразование JSON или XML-ответа в объекты может позволить реализовать более умные и структурированные ассерты.
❗️Минусы: скорее всего, придётся писать кастомные проверки или обрабатывать объекты вручную.
💡 Мое дополнение: это мой основной способ работы с API ответами. Часто эти модельки (DTO классы) пригодятся и для создания в самих запросах. Существуют сервисы, которые генерируют эти классы на основе JSON или схемы, например: jsonschema2pojo. Кастомные проверки можно делать уже средствами JUnit 5, TestNG или AssertJ. Можно использовать SoftAssertions либо даже сделать проверки в виде steps и логировать это в Allure. Есть и другие подходы, например, Fluent Interface/method chaining.
🧩 Переосмысление дизайна API
А действительно ли API должен возвращать столько полей? Может быть, стоит переосмыслить его структуру?
Большие ответы могут быть признаком не самого лучшего дизайна API и даже увеличивать риск уязвимостей вроде Broken Object Property Level Authorisation или Excessive Data Exposure.
❗️Минусы: вероятность того, что команда разработки или продуктовая команда согласятся на изменения — низкая, особенно если API уже активно используется другими системами.
💡 Мое дополнение: у меня был опыт работы в команде, которая пилила монолит на микросервисы и оптимизировала часть ответов. Для синхронизации с другими системами я внедрял контрактное тестирование. С его помощью можно было проверить, что изменения в нашем сервисе не ломают тесты другим командам.
💡 Добавлю еще варианты от себя:
• Тестирование с помощью then блока самого RestAssured. Под капотом используется Hamcrest, вариант подходит, если из большого ответа нужно проверять только часть. Например, ответ вернул всю информацию о корзине товаров на E-commerce сайте, а вам нужно проверить только количество товара с 1 на 2.
then().body("quantity", equalTo(2));
• Через RestAssured можно и схему сравнить:
then().body(matchesJsonSchemaInClasspath("jsonSchema/petSchema.json"));
• В AssertJ есть возможность сравнить 2 объекта с указанием, какие поля нужно игнорировать:
assertThat(actualUser).usingRecursiveComparison().ignoringFields("id").isEqualTo(expectedUser);
Больше примеров можно найти в одном из моих проектов с курса по автоматизации: SimpleAPITests и ExtendedAPITests
>>Click here to continue<<
