1. Основы HTTP и протокола REST для инженера по автоматизации
Основы HTTP и протокола REST для инженера по автоматизации
Представьте, что вы вызываете такси через мобильное приложение. В ту же секунду, как вы нажимаете кнопку, происходит невидимый диалог: ваш смартфон отправляет запрос на сервер, сервер проверяет наличие машин, рассчитывает стоимость и возвращает ответ. Если в этом диалоге произойдет сбой — например, сервер не поймет формат ваших координат или вернет ошибку авторизации — поездка не состоится. Для инженера по автоматизации тестирования понимание механики этого диалога, основанного на протоколе HTTP и архитектурном стиле REST, является фундаментом. Без глубокого знания «правил игры» между клиентом и сервером невозможно построить надежный фреймворк, который будет не просто проверять наличие ответа, но и гарантировать корректность бизнес-логики системы.
Анатомия HTTP-запроса: что именно мы автоматизируем
HTTP (HyperText Transfer Protocol) — это прикладной протокол передачи данных, работающий по модели «клиент-сервер». В контексте автоматизации API нашим клиентом будет Java-код (с использованием библиотеки Rest Assured), а сервером — тестируемое приложение. Каждый раз, когда мы пишем тест, мы конструируем объект запроса, который состоит из четырех критически важных компонентов.
Стартовая строка (Start Line)
Здесь определяется метод (Verb), целевой ресурс (URI) и версия протокола. Для автоматизатора метод — это первое, на что стоит обратить внимание, так как он определяет семантику действия. Если разработчик используетGET для удаления данных, это серьезное нарушение принципов REST, которое должно быть отражено в баг-репорте.Заголовки (Headers)
Заголовки — это метаданные. Они не содержат саму суть сообщения, но объясняют, как его интерпретировать. В автоматизации мы чаще всего сталкиваемся с: *Content-Type: сообщает серверу, в каком формате мы прислали данные (например, application/json).
* Accept: говорит серверу, какой формат ответа ожидает клиент.
* Authorization: передает токены (Bearer, Basic) для проверки прав доступа.Ошибка в заголовке часто приводит к коду (Unsupported Media Type) или (Unauthorized), и умение быстро локализовать проблему в заголовках экономит часы отладки тестов.
Тело запроса (Body)
Это полезная нагрузка. В современных REST API это почти всегда JSON-объект. При проектировании фреймворка на Java мы будем превращать (сериализовать) Java-объекты в эту строку JSON, чтобы передать данные о новом пользователе, заказе или товаре.Методы HTTP и их семантическая роль
Часто начинающие автоматизаторы путают назначение методов, полагая, что «технически всё можно передать через POST». Однако REST диктует строгую логику, нарушение которой ведет к хрупкости системы.
GET: получение данных
МетодGET предназначен только для чтения. Он должен быть идемпотентным и безопасным. Безопасность в данном контексте означает, что вызов метода не изменяет состояние ресурса на сервере.
> Идемпотентность — это свойство операции, при котором повторный вызов одного и того же запроса дает тот же результат, что и первый, и не вызывает дополнительных побочных эффектов.
>
> RFC 7231, Hypertext Transfer Protocol (HTTP/1.1): Semantics and ContentДля это означает: сколько бы раз вы ни запрашивали профиль пользователя с ID 123, данные профиля не должны измениться только от факта запроса.
POST: создание и обработка
POST используется для создания новой сущности или выполнения сложной операции, которая не вписывается в другие методы (например, запуск процесса обработки данных). В отличие от GET, POST не является идемпотентным: два одинаковых запроса на создание заказа создадут два разных заказа в базе данных.PUT vs PATCH: полное и частичное обновление
Это тонкий момент, который часто становится темой на собеседованиях. *PUT заменяет ресурс целиком. Если вы отправляете PUT /users/1 с телом {"name": "Ivan"}, а раньше у пользователя было еще и поле age, то после PUT поле age может быть стерто или установлено в значение по умолчанию, если сервер не обработает это иначе. PUT идемпотентен: повторная замена ресурса на тот же самый не изменит состояние системы дальше первого раза.
* PATCH вносит частичные изменения. Мы передаем только те поля, которые хотим изменить. PATCH не обязательно идемпотентен (хотя часто стремится к этому), так как логика обновления может зависеть от текущего состояния.DELETE: удаление
Удаляет ресурс. Метод идемпотентен: если мы удалили пользователя один раз, повторный запрос вернет тот же результат (пользователя нет), хотя статус-код может отличаться ( при первом удалении и при последующих, но состояние сервера остается стабильным — ресурса нет).Структура URL и параметры: Query vs Path
Правильное понимание того, куда именно мы отправляем запрос, критично для параметризации тестов. URL состоит из базового адреса (Base URL), пути (Path) и параметров запроса (Query Parameters).
Рассмотрим пример:
https://api.store.com/v1/products/105?currency=usd
https://api.store.com/v1/ — Base URL. Обычно выносится в конфигурацию фреймворка./products/105 — Path Parameter. Здесь 105 — это уникальный идентификатор ресурса. В Rest Assured мы будем использовать плейсхолдеры типа {productId}, чтобы подставлять разные значения.?currency=usd — Query Parameter. Используется для фильтрации, сортировки или пагинации. Параметры запроса всегда идут после знака ?.Важное правило: если вы хотите идентифицировать конкретный объект, используйте Path. Если вы хотите отфильтровать список объектов (например, «покажи мне все красные кроссовки»), используйте Query.
Коды состояния HTTP: язык сервера
Автоматизированный тест в первую очередь проверяет Status Code. Это трехзначное число, которое сообщает о результате операции. Как инженеры, мы должны различать классы кодов:
| Класс | Значение | Примеры для QA |
| :--- | :--- | :--- |
| 2xx (Success) | Все хорошо. Запрос принят и обработан. | 200 OK (успех), 201 Created (создано после POST). |
| 3xx (Redirection) | Нужно пойти по другому адресу. | В API-тестах встречается редко, обычно обрабатывается библиотекой автоматически. |
| 4xx (Client Error) | Ошибка на нашей стороне (в тесте или в данных). | 400 Bad Request (невалидный JSON), 401 Unauthorized (забыли токен), 404 Not Found (неверный ID). |
| 5xx (Server Error) | Упал бэкенд. Это всегда баг (или проблема инфраструктуры). | 500 Internal Server Error (NullPointerException в коде), 503 Service Unavailable. |
Особое внимание стоит уделить коду (Unprocessable Entity). Он часто используется в REST API, когда формат запроса верный (JSON валиден), но данные не проходят бизнес-валидацию (например, возраст пользователя отрицательный).
Принципы архитектуры REST
REST (Representational State Transfer) — это не стандарт и не протокол, а набор архитектурных ограничений. Если система им следует, она называется RESTful. Для автоматизатора понимание этих принципов помогает предугадать поведение системы.
Client-Server
Разделение ответственности. Клиент не заботится о хранении данных, сервер не заботится о пользовательском интерфейсе. Это позволяет нам тестировать API в изоляции от фронтенда.Stateless (Отсутствие состояния)
Это фундаментальный принцип для автоматизации. Сервер не должен помнить, что вы делали в предыдущем запросе. Каждый запрос должен содержать всю информацию, необходимую для его обработки (включая токены аутентификации). Почему это важно для нас? Это позволяет запускать тесты параллельно и в любом порядке. Если тест А зависит от того, что в тесте Б мы «залогинились» и сервер это «запомнил» в сессии — такой API трудно масштабировать, а тесты будут постоянно падать из-за гонки данных.Uniform Interface (Единообразие интерфейса)
Все ресурсы должны быть доступны через универсальные идентификаторы (URI) и манипуляция ими должна происходить через стандартные методы (GET, POST и т.д.). Если для получения списка книг используетсяGET /books, а для получения списка авторов — POST /getAuthors, то интерфейс не единообразен, и это усложняет написание общего кода во фреймворке.Cacheable
Ответы сервера должны помечаться как кешируемые или нет. В тестировании это важно учитывать: иногда вы можете получать старые данные из кеша, если не настроите заголовкиCache-Control в своих тестах.Работа с JSON: формат обмена данными
Хотя REST теоретически поддерживает XML, YAML и даже Plain Text, современным стандартом де-факто является JSON (JavaScript Object Notation). Как инженеры по автоматизации на Java, мы будем постоянно сталкиваться с необходимостью парсинга JSON.
Структура JSON проста:
* Объекты в фигурных скобках { "key": "value" }.
* Массивы в квадратных скобках [1, 2, 3].
* Типы данных: String, Number, Boolean, Null.
Пример сложного ответа API:
В Java-коде мы не хотим работать с JSON как с «просто строкой». Мы будем использовать библиотеки Jackson или Gson для превращения этого текста в объекты (POJO — Plain Old Java Objects). Это позволит нам обращаться к полям через точку: product.getSpecs().getDpi(), что делает тесты читаемыми и поддерживаемыми.
Идемпотентность и безопасность на практике
Давайте разберем сценарий, который часто встречается на технических собеседованиях. Представьте, что вы тестируете API денежных переводов.
Запрос: POST /transfers с телом {"from": 1, "to": 2, "amount": 100}.
Если этот запрос не будет защищен механизмом идемпотентности (например, через специальный заголовок Idempotency-Key), то при сетевом сбое клиент может отправить запрос повторно. Если сервер обработает оба запроса, с пользователя спишется вместо .
Хотя POST по стандарту не идемпотентен, в критических системах разработчики реализуют этот механизм искусственно. Как автоматизатор, вы должны проверить: что произойдет, если я отправлю один и тот же POST запрос дважды с одинаковым ключом идемпотентности? Система должна вернуть успех, но не совершить транзакцию второй раз.
Спецификация API: Swagger и OpenAPI
Прежде чем писать тесты, автоматизатор должен понять, как работает API. В современных проектах это делается через спецификацию OpenAPI (ранее известную как Swagger).
OpenAPI — это «контракт» между фронтендом, бэкендом и тестированием. В нем описаны все эндпоинты, форматы запросов, обязательные поля и возможные ответы. Для нас это:
email обязательное, а API позволяет создать пользователя без него — это баг.swagger.json или openapi.yaml).Нюансы тестирования REST API
При переходе из ручного тестирования в автоматизацию важно сместить фокус с «проверки кнопок» на «проверку контрактов и состояний».
Валидация типов данных
Если API ожидает число в полеprice, автоматизированный тест должен проверить, как система реагирует на строку, на слишком большое число (overflow) или на отрицательное значение.Проверка структуры (Schema Validation)
Недостаточно проверить, чтоstatus code = 200. Нужно убедиться, что структура JSON не изменилась: не пропали ли обязательные поля, не изменились ли их типы. Для этого в Java-автоматизации используется JSON Schema Validation — мы сравниваем ответ сервера с эталонной схемой.Обработка динамических данных
В API-тестах мы часто сталкиваемся с данными, которые меняются при каждом запросе (например,id, createdAt, token). Мы не можем захардкодить «2023-10-27» в ожидаемый результат. Нам придется использовать регулярные выражения, матчеры (Hamcrest/AssertJ) или просто проверять, что поле соответствует формату даты, не привязываясь к конкретному значению.Роль заголовков в безопасности и управлении контентом
Рассмотрим подробнее заголовок Authorization. В автоматизации API мы редко сталкиваемся с формой логина. Чаще всего мы работаем с JWT (JSON Web Token).
Процесс выглядит так:
POST /login.Authorization: Bearer <token> для всех последующих запросов.Если вы проектируете фреймворк, вам нужно предусмотреть механизм автоматического подкладывания этого токена (Request Specification в Rest Assured), чтобы не прописывать его в каждом тесте вручную.
Другой важный заголовок — User-Agent. Иногда серверы блокируют запросы, если в User-Agent указано что-то подозрительное или если он вовсе отсутствует. Библиотеки автоматизации часто подставляют свои значения (например, Apache-HttpClient), и в редких случаях вам придется маскировать свои тесты под обычный браузер.
Итоги понимания протокола для архитектуры фреймворка
Почему мы начали курс именно с теории HTTP и REST, а не с написания кода на Java? Потому что архитектура вашего будущего фреймворка будет зеркальным отражением этих знаний.
* Зная о Base URL и Path, вы создадите класс конфигурации и отдельные классы для сервисов (например, UserService, OrderService).
* Понимая структуру JSON, вы выберете библиотеку Jackson для создания POJO-моделей.
* Зная о Stateless природе REST, вы сможете запускать свои тесты в 10 потоков в Docker-контейнерах, не боясь, что они помешают друг другу.
* Понимая HTTP-методы, вы построите удобный DSL (Domain Specific Language) в тестах, где вызов userClient.create(user) будет внутри себя инкапсулировать POST запрос с нужными заголовками.
Глубокое понимание протокола превращает автоматизатора из «человека, который пишет скрипты» в инженера, который понимает, как данные текут по венам распределенной системы. Это позволяет находить ошибки не только в реализации, но и в самом проектировании API еще до того, как будет написана первая строчка кода фронтенда.