go test: пакеты, cache, race, count и run

go test компилирует пакет и исполняет его tests, examples и fuzz targets согласно выбранным флагам. ./... рекурсивно выбирает пакеты текущего модуля, но не заменяет явно спланированные integration- или e2e-проверки.

Зачем это на интервью

Важно показать, как из «тест зелёный локально» получить воспроизводимое доказательство: выбрать пакет, отключить cache при диагностике, повторить flaky case и проверить конкурентный путь.

Минимум для E4

  • Запускать всё: go test ./...; один пакет: go test ./internal/auth.
  • Фильтровать полным regexp: go test ./... -run '^TestLogin$'.
  • Повторять без cache: go test ./... -count=1; ловить flaky: -count=100.
  • Запускать race detector: go test -race ./....
go test ./...
go test ./internal/cache -run '^TestStore/(miss|hit)$' -count=1 -v
go test -race ./internal/cache -count=20
go test ./... -shuffle=on

Углубление для E5/Senior

Cache ускоряет успешные package tests и зависит от исходников, окружения и флагов. Не обвиняйте cache без проверки -count=1; напротив, не выключайте его постоянно в обычном feedback loop. -run применяет regexp к имени теста и subtest; якоря не дают случайно запустить похожие тесты. -count повторяет тестовый binary; -shuffle=on помогает обнаружить зависимость от порядка.

Race detector инструментирует memory accesses и сообщает о наблюдённых data races. Он существенно медленнее и требует выполнения конфликтующего schedule; чистый прогон не является математическим доказательством. В CI полезны -race на поддерживаемой платформе и тесты, которые реально создают конкуренцию. Исправление — синхронизация/владение данными, не time.Sleep.

Ключевые понятия

ФлагНазначение
./...пакеты под текущим модулем
-run reотбор Test/Benchmark/Fuzz по regexp
-count=nповторение, 1 отключает test cache
-raceобнаружение выполненных data races
-shuffleизменение порядка тестов и subtests

Типовые вопросы

  1. Почему -count=1 полезен? — Исключает использование test cache при проверке воспроизводимости.
  2. Почему -run TestX рискован? — Это regexp; без ^...$ могут совпасть другие имена.
  3. Находит ли -race все гонки? — Нет, только гонки на реально выполненных путях и interleavings.
  4. Нужно ли всегда тестировать ./...? — Перед merge обычно да; в цикле разработки узкий пакет быстрее, но не заменяет полный gate.
  5. Как расследовать flaky test? — Зафиксировать seed/окружение, повторить -count, включить -shuffle, убрать зависимости от времени и глобального состояния.

Практика

  • Напишите тест с subtests и запустите ровно один. Готово: команда с якорным -run запускает ожидаемое имя и только его.
  • Внесите намеренную race в счётчик. Готово: -race сообщает конфликт, а исправление mutex/atomic проходит -count=50.

Частые ошибки и ловушки

  • Интерпретировать cache hit как отсутствие исполнения теста при расследовании.
  • Считать -race поводом не проектировать ownership данных.
  • Прятать flaky test за retry вместо устранения причины.

Связанные темы

Инструменты Go · Тестирование · Конкурентность Go

Источники