Как отключить кэширование тестов в Go и принудительно перезапускать их?
Почему Go кэширует тесты?
Кэширование тестов — это полезная оптимизация, встроенная в Go начиная с версии 1.10. Когда вы запускаете go test, Go анализирует: исходный код теста, импортируемые пакеты, переменные окружения и флаги командной строки. Если ничего не изменилось с прошлого запуска, Go просто возвращает кэшированный результат, помеченный как (cached). Это экономит время, особенно в больших проектах.
Однако это может мешать, когда вы:
- Тестируете код, который зависит от внешних ресурсов (файлы, БД, сеть).
- Проверяете рандомизированное поведение.
- Хотите убедиться, что тесты действительно проходят после изменений.
Как принудительно отключить кэширование?
Самый простой и рекомендуемый способ — использовать флаг -count=1. Он указывает Go выполнить тест ровно один раз, игнорируя кэш:
go test -count=1 ./...
Это работает для всех тестов в текущем пакете и его подпакетах. Флаг -count можно комбинировать с другими флагами, например:
go test -v -count=1 -run TestAddition ./...
Альтернативные методы
Если вы хотите очистить весь кэш тестов разово, используйте:
go clean -testcache
Это удалит все кэшированные результаты тестов, но не затронет кэш сборки. Для полной очистки всех кэшей Go:
go clean -cache
Как настроить кэширование глобально?
Go не предоставляет глобальной настройки для отключения кэширования тестов. Однако вы можете:
- Создать алиас в shell:
alias gotest='go test -count=1' - Использовать Makefile:
test: go test -count=1 ./... - Настроить IDE (например, VS Code) добавлять флаг
-count=1в конфигурацию запуска тестов.
Когда кэширование не работает?
Go автоматически отключает кэширование, если:
- Используется флаг
-race(детектор гонок). - Задан флаг
-benchили-benchmem. - Тест вызывает
t.Parallel()(но не всегда — зависит от версии). - Переменная окружения
GOFLAGS=-count=1установлена.
Также кэш не применяется к тестам, которые используют testing.Short() или зависят от файлов вне модуля (через //go:embed).
Важные замечания
Не рекомендуется использовать go clean -testcache перед каждым запуском — это излишне и медленно. Флаг -count=1 — более элегантное решение. Также помните, что кэширование работает на уровне пакета: если вы изменили один файл в пакете, кэш для всего пакета инвалидируется автоматически.
Пример рабочего скрипта для CI/CD, который всегда запускает тесты свежими:
#!/bin/bash
set -e
echo "Running tests without cache..."
go test -count=1 -v ./...
Итог: используйте -count=1 для принудительного перезапуска тестов, а для разовой очистки — go clean -testcache.
Дополнительный подход: флаг -count=1 как стандарт
Коллега верно описал основной метод. Хочу добавить, что в современных проектах часто используют переменную окружения GOFLAGS, чтобы не писать -count=1 каждый раз. Просто добавьте в свой .bashrc или .zshrc:
export GOFLAGS="-count=1"
Тогда любой вызов go test будет автоматически игнорировать кэш. Это удобно для разработки, но в CI/CD лучше явно указывать флаг, чтобы поведение было очевидным.
Другой вариант: инвалидация кэша через файлы
Если вам нужно, чтобы кэш сбрасывался при изменении определённых файлов (например, конфигов), можно использовать трюк с тестовыми флагами. Добавьте в тест чтение файла или переменной окружения:
func TestConfig(t *testing.T) {
data, _ := os.ReadFile("config.yaml")
// тест, зависящий от содержимого файла
}
Go автоматически отслеживает чтение файлов через os.ReadFile и инвалидирует кэш при их изменении. Но это работает только для файлов, указанных явно в коде теста.
Для бенчмарков
Если вы используете бенчмарки, кэширование отключается автоматически, но можно принудительно задать количество итераций:
go test -bench=. -benchtime=10x -count=1
Помните: кэширование — друг, а не враг. Не отключайте его без необходимости, особенно в больших проектах с сотнями тестов.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги