Сервис должен отдавать свежие данные из кэша без обращения к внешнему API. Как построить интеграционную проверку этого поведения?
Подготовьте в кэше свежую запись, вызовите проверяемый сервис и одновременно настройте мок внешнего API так, чтобы любой неожиданный вызов немедленно проваливал тест. Проверка должна подтвердить корректный ответ клиенту и отсутствие обращения к зависимости.
По мере роста распределённых систем кэширование стало способом уменьшить задержку, нагрузку на внешние зависимости и влияние их временной недоступности. Однако обычная проверка итогового HTTP-ответа не показывает, был ли он получен из кэша или заново рассчитан через внешний API.
Интеграционные тесты поэтому стали проверять не только данные на выходе, но и важные взаимодействия между компонентами. Для кэш-сценария существенен отрицательный контракт: при выполнении определённых условий внешний вызов не должен происходить.
Если мок внешнего API всегда возвращает успешный ответ, тест может пройти даже при неисправном кэше или при полном обходе кэша. В рабочей системе это приведёт к лишней задержке, росту нагрузки и зависимости от доступности внешнего сервиса.
Особенно опасна проверка только содержимого ответа. Кэш и внешний API могут вернуть одинаковые данные, поэтому ошибка в выборе источника останется незамеченной. Дополнительный риск создаёт неконтролируемое время: запись, считавшаяся свежей при подготовке, может стать просроченной во время теста.
Тест должен изолированно подготовить свежую запись в том же кэше, который использует приложение, и зафиксировать контролируемое время. Затем он вызывает публичный интерфейс проверяемого сервиса.
Мок внешнего API следует настроить не на обычный успешный ответ, а на запрет любого обращения. Практически это означает, что неожиданный вызов должен сразу считаться ошибкой; итоговая проверка числа вызовов полезна дополнительно, но менее надёжна, если тест прекращается раньше.
После вызова проверяют две вещи: ответ содержит ожидаемые данные из кэша, а внешний API не вызывался. Отдельно нужны тесты для границы срока годности: свежая запись должна использоваться, просроченная — обрабатываться по предусмотренному сценарию, например через обращение к источнику или возврат ошибки.
Нельзя подменять весь кэш простым словарём, если цель — проверить интеграцию с конкретным хранилищем. Такой подход проверит только логику выбора ветки. Для проверки интеграции используют тестовый экземпляр кэша либо его совместимый адаптер, а внешнюю систему заменяют моками или контрактным стендом.
У проверки есть компромисс: строгий запрет вызова делает тест точным для требования «не обращаться к зависимости», но связывает его с конкретной границей кэширования. Поэтому изменение архитектуры может потребовать обновления теста даже без изменения пользовательского поведения. Контракт внешнего API при этом нужно проверять отдельно: тест с запретом вызова его не покрывает.
Сервис профилей должен возвращать данные из распределённого кэша в течение пяти минут. Тест заранее помещал профиль в кэш, но мок внешнего сервиса всегда отвечал тем же профилем. Когда разработчик случайно отключил чтение из кэша, тест продолжил проходить, хотя каждый запрос стал зависеть от внешней системы.
Рассматривались два варианта. Первый — сравнивать время ответа; он прост, но нестабилен и зависит от загрузки среды. Второй — проверять взаимодействие с моками; он надёжнее, но не подтверждает работу реального кэш-хранилища.
Выбрали комбинацию: тестовый экземпляр кэша с контролируемым временем и мок внешнего API, запрещающий любые вызовы. В результате ошибка обхода кэша стала обнаруживаться сразу, а отдельные проверки контракта внешнего API сохранили независимость от сценариев кэширования.
Нет. Нужно также проверить источник и корректность возвращённых данных. Пустой кэш, неверный ключ или ошибка чтения могут привести к отсутствию внешнего вызова и одновременно к неправильному ответу. Минимальная проверка должна подтверждать и ожидаемый результат, и отсутствие обращения к зависимости.
Время должно быть управляемой зависимостью: тест фиксирует текущий момент или использует абстракцию часов, которую можно продвинуть. Затем отдельно проверяются состояния до границы, на границе и после неё. Ожидание реального истечения срока делает тест медленным и подверженным сбоям планировщика.
Мок воспроизводит только заранее заданные ожидания теста и может не отражать фактический формат запросов и ответов поставщика. Поэтому проверка отсутствия вызова ничего не говорит о совместимости в ветке промаха кэша. Для неё нужен отдельный контрактный или интеграционный тест с реальной тестовой системой либо с проверяемым контрактом поставщика.