Сервис поддерживает условный GET, а клиент уже сохранил представление ресурса. Какой основной контракт должен проверить интеграционный тест при отсутствии изменений ресурса?
GET /profiles/42 HTTP/1.1
If-None-Match: "v7"
HTTP/1.1 304 Not Modified
ETag: "v7"
Интеграционный тест должен проверить, что при совпадении значения If-None-Match с текущим ETag сервер возвращает 304 Not Modified, не передаёт тело ресурса и сохраняет согласованные заголовки кеширования. Клиент при этом должен использовать ранее сохранённое представление, а не ожидать новый JSON в ответе.
Условные HTTP-запросы появились для уменьшения объёма передаваемых данных и задержки при повторном чтении неизменившихся ресурсов. Клиент сначала получает представление с валидатором, например ETag, а затем сообщает серверу этот валидатор в следующем запросе.
Если ресурс не изменился, сервер может ответить 304 Not Modified без повторной передачи содержимого. Такой механизм отделяет проверку актуальности ресурса от его полной загрузки.
Ошибка в контракте может проявиться в нескольких формах: сервер возвращает 200 с лишним телом, отправляет 304 с некорректным или изменившимся валидатором либо клиент пытается разобрать пустое тело как JSON. В результате возрастает трафик, нарушается кеширование или возникают ошибки десериализации.
Проверка только статус-кода недостаточна. Нужно подтвердить связь между значением If-None-Match, текущим ETag, отсутствием тела и поведением клиента при использовании кешированной версии.
Для неизменившегося ресурса тест должен отправить условный запрос:
Основные инварианты таковы:
Тест также должен проверять противоположный случай: если ETag изменился, сервер обязан вернуть обычное успешное представление ресурса, например 200, с новым телом и новым валидатором. Иначе клиент продолжит использовать устаревшие данные.
Важно не требовать от каждого API одинакового набора заголовков: точный состав зависит от принятого HTTP-контракта и политики кеширования. Кроме того, ETag должен сравниваться с учётом правил, объявленных контрактом; нельзя безоговорочно считать любую текстовую разницу единственным критерием корректности.
Мобильный клиент повторно запрашивал профиль пользователя. Сервер при совпадающем ETag возвращал 304, но интеграционный тест проверял только статус 2xx и всегда пытался десериализовать тело. В общем прогоне это приводило к ошибке разбора пустого ответа.
Рассматривались два варианта. Можно было изменить сервер и всегда возвращать 200 с полным JSON: это упростило бы клиента, но увеличило трафик и фактически отключило преимущество условных запросов. Можно было научить клиент обрабатывать 304 и добавить проверку контракта: решение требовало более точной тестовой логики, зато сохраняло HTTP-модель кеширования.
Выбрали второй вариант. Тест стал проверять пару «валидатор запроса — статус и тело ответа», а клиент при 304 оставлял кешированное представление. Это устранило ошибку десериализации и сохранило экономию трафика.
Нет, только если это предусмотрено контрактом и запрос действительно допускает условную обработку. Поведение может зависеть от метода, политики кеширования, авторизации и других условий запроса. Тест должен фиксировать не абстрактное правило «совпал ETag — всегда 304», а конкретный контракт данного API.
Пустое тело само по себе не доказывает корректность условного ответа. Сервер может вернуть ошибочный статус, потерять ETag или сообщить валидатор, не соответствующий представлению. Нужно проверять совокупность признаков: статус, валидатор, отсутствие тела и последующее использование клиентом кешированной версии.
Тест должен использовать управляемые данные и явно изменить ресурс либо его версию перед вторым запросом. После этого ожидается обычный ответ с актуальным представлением и новым ETag, а не 304. Такой сценарий выявляет ошибку, при которой сервер сравнивает условие с устаревшим кешем или возвращает старую версию данных.