Тестовые стенды: как разрабатывать, не разоряясь на токенах

Неожиданный счёт в конце месяца чаще приходит не из продакшена. Его приносит цикл по тестовым данным, запущенный в пятницу и отработавший все выходные.

СРЕДЫРазработка не должна стоить как продакшенНа стенде почти всегда хватает лёгкой моделиЛокальнозаглушки и записанные ответыДоля расхода≈ 0 ₽Тестовый стендлёгкая модель, малый лимитДоля расходаединицы процентовПродакшенрабочая модель и полныйлимитДоля расходаосновной бюджет
На стенде почти всегда хватает лёгкой модели, а локально можно обойтись без запросов вовсе

Откуда берётся расход при разработке

Причин несколько, и все выглядят безобидно по отдельности.

Отладочные прогоны: чтобы проверить одну правку, разработчик гоняет набор из ста примеров, и делает это двадцать раз за день.

Автотесты, которые дёргают живую модель при каждом запуске сборки.

Забытые фоновые задачи на стенде, продолжающие обрабатывать данные после того, как о них перестали думать.

Копия продакшен-нагрузки на тестовом контуре, оставленная «для реалистичности».

Каждый пункт по отдельности кажется мелочью. Вместе они регулярно дают половину месячного счёта.

Чем заменить живые запросы

ПРИЁМЫЧем заменить живые запросы при разработкеЗаписанные ответыодин раз сохранили — гоняем бесплатноЗаглушка вместо моделипроверка кода вокруг вызоваЛёгкая модель на стендеформа ответа та же, цена другаяУрезанный тестовый наборполный прогон только перед выкатомСамый частый источник неожиданного счёта — не продакшен, а цикл по тестовым данным, запущенный на выходных.
Самый частый источник неожиданного счёта — цикл по тестовым данным, запущенный на выходных

**Записанные ответы.** Один раз сохранили результат для набора примеров — дальше гоняете сколько угодно бесплатно. Подходит для проверки кода вокруг вызова: разбора ответа, обработки ошибок, записи в базу.

**Заглушка вместо модели.** Возвращает заранее заданный ответ нужной формы. Незаменима в автотестах: они должны проверять ваш код, а не качество модели.

**Лёгкая модель на стенде.** Форма ответа та же, цена другая на порядок. Годится для ручной проверки интерфейса и сквозных сценариев.

**Урезанный набор при отладке.** Пять примеров вместо пятидесяти на каждой итерации, полный прогон — только перед выкатом.

Что должно остаться живым

Не всё можно заменить заглушкой, иначе стенд перестаёт что-либо проверять.

  • Оценку качества ответов — она в принципе требует настоящей модели.
  • Проверку структурированного вывода на новой версии.
  • Сквозной прогон перед выкатом.
  • Проверку интеграций с функциями, если формат вызова изменился.

Правило простое: живые запросы нужны там, где вы проверяете поведение модели. Везде, где проверяется ваш код, достаточно заглушки.

Разделение бюджетов

Отдельный ключ на каждое окружение — не только вопрос безопасности, но и вопрос учёта. Пока стенд и продакшен ходят по одному ключу, вы не узнаете, сколько стоит разработка.

Лимиты стоит выставить сразу и заведомо небольшие. Стенд, упёршийся в лимит, — это неудобство на десять минут. Стенд без лимита — это счёт, который обнаруживается в конце месяца.

Отдельно проверьте ключ, который лежит у подрядчика. Именно там чаще всего обнаруживается забытый процесс, работающий уже третью неделю.

Локальная разработка

На машине разработчика живых запросов обычно можно избежать полностью. Записанные ответы плюс заглушка покрывают почти все задачи, а необходимость обратиться к настоящей модели возникает несколько раз в неделю.

Полезная привычка — держать набор записанных ответов в репозитории. Он же служит документацией: видно, что именно возвращает модель, без необходимости это выяснять.

Как записывать ответы

Механика простая. При первом запуске вызов идёт в живую модель, ответ сохраняется в файл, ключом служит содержимое запроса. При следующих запусках, если файл найден, вызов не делается вовсе.

Переключение между режимами — одна переменная окружения: записывать, воспроизводить или ходить в живую модель. В автотестах включён режим воспроизведения, локально обычно тоже, а на сквозных прогонах — живые запросы.

Записи стоит хранить в репозитории вместе с кодом. Они небольшие, зато дают воспроизводимость: коллега запускает тесты и получает ровно те же результаты, не тратя ни рубля.

Обновляются записи по команде, когда вы сознательно хотите проверить поведение на новой версии модели. Тогда старые файлы удаляются и набор перезаписывается заново.

Пример расчёта

Команда из четырёх разработчиков, у каждого по двадцать отладочных прогонов в день на наборе из пятидесяти примеров. Это четыре тысячи вызовов в день только на отладку — сопоставимо с небольшим продакшеном.

Перевод отладки на записанные ответы и урезанный набор из пяти примеров снижает эту цифру до нескольких десятков вызовов. Полный прогон при этом никуда не девается — он просто делается один раз перед выкатом, а не двадцать раз в день на каждого разработчика.

Ровно та же арифметика применима к автотестам: сборка, запускающаяся при каждом коммите, за месяц набирает объём, который заметен в счёте.

Что настроить один раз

  • Отдельные ключи и лимиты на каждое окружение.
  • Заглушку, включаемую одной переменной окружения.
  • Автотесты, которые никогда не ходят в живую модель.
  • Уведомление о расходе на стенде выше порога.
  • Правило: любой цикл по данным запускается только с явным подтверждением.

Полдня работы — и класс проблем с внезапными счетами закрывается. А заодно исчезает страх лишний раз запустить тесты, который заметно замедляет разработку.

Напоследок стоит договориться, кто и когда смотрит на расход стендов. Обычно достаточно раз в неделю бросить взгляд на суточную сводку по ключам разработки. Пять минут внимания вылавливают забытый процесс за день-два, а не за месяц — и именно эта привычка, а не технические ограничения, чаще всего избавляет команду от неприятных счетов.

Написать