Программирование GoТестированиеИнженер по автоматизированному тестированию на Go

При отладке table driven теста выяснилось, что несколько кейсов имеют одинаковые имена. Почему фильтрация s...

При отладке table-driven теста выяснилось, что несколько кейсов имеют одинаковые имена. Почему фильтрация subtest по имени может запускать не один кейс?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Потому что Go делает имена subtest уникальными, добавляя к повторяющимся именам суффиксы вроде #01, но фильтр обычно сопоставляется с именем как регулярное выражение. Поэтому фильтр по общей части имени может совпасть сразу с исходным кейсом и его дубликатами.

Исторический контекст

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

Постановка проблемы

В table-driven тесте одинаковые названия часто возникают из-за обобщённого поля вроде valid или error. При полном запуске тесты могут проходить, но при локальной отладке фильтр по имени запустит несколько похожих кейсов, создавая впечатление, что проверяется только один сценарий.

Это ухудшает воспроизводимость результата: разработчик может исправить не тот кейс или ошибочно решить, что дефект устранён. Суффиксы, автоматически добавляемые Go, не заменяют осмысленные уникальные имена, поскольку они зависят от порядка появления дубликатов.

Подробное решение

При совпадении имён Go сохраняет отдельные subtest, но уникализирует их отображаемые имена. Например, два кейса с именем empty могут отображаться как empty и empty#01.

Фильтрация subtest выполняется по компонентам полного имени и использует регулярные выражения. Поэтому шаблон, совпадающий с empty, может совпасть и с empty#01: он проверяет общую часть, а не смысловую уникальность кейса.

func TestParse(t *testing.T) { cases := []struct { name string in string }{ {"empty", ""}, {"empty", " "}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { _ = tc.in }) } }

Надёжное решение — задавать каждому кейсу стабильное уникальное имя: например, empty_input и spaces_input. Не следует полагаться на автоматически добавленные #01, поскольку изменение порядка таблицы изменит адрес кейса и результат фильтрации.

Ситуация из практики

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

Вариант с полным описанием входа давал читаемые, но слишком длинные имена. Выбрали короткие уникальные идентификаторы missing_token и bad_encoding, оставив подробности входных данных в структуре кейса. Это сделало отчёты понятными, а адресный запуск — стабильным.

Что кандидаты часто упускают

1. Вопрос: Означает ли суффикс #01, что Go объединил два одинаковых кейса?

Ответ: Нет. Каждый вызов t.Run создаёт отдельный subtest со своим выполнением, результатом и временем. Суффикс нужен только для устранения неоднозначности имени; он не меняет входные данные и не объединяет результаты.

2. Вопрос: Как сделать адресный запуск кейса устойчивым к изменению порядка строк в таблице?

Ответ: Нужно использовать уникальное содержательное имя, не зависящее от позиции кейса. Имя должно описывать проверяемый сценарий, например timeout_from_store, а не быть case_0 или автоматически созданным case#01. Тогда перестановка строк не изменит способ обращения к тесту.

3. Вопрос: Почему уникальные имена важны даже при отсутствии ручного запуска отдельных subtest?

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