🧪 Table-Driven Tests: Хватит плодить функции-клоны — 23 апреля 2026 г. в 13:57:04.103
🧪 Table-Driven Tests: Хватит плодить функции-клоны Проверяю PR джуниора. Файл на 500 строк, из них 450 - это тесты. Смотрю внимательнее, а там Test_ValidateEmail_Empty, Test_ValidateEmail_NoAt, Test_ValidateEmail_Valid... Каждая функция копирует предыдущую на 90%. Любое изменение сигнатуры ValidateEmail заставит переписывать весь этот ад руками. Коллеги, в Go так не делают. Наш путь - Table-Driven Tests. Идея гениально проста: мы отделяем данные от логики тестирования. Логика пишется один раз, а тест-кейсы складываются в компактную таблицу (обычно это слайс анонимных структур). Как это выглядит на практике: func TestDivide(t *testing.T) { // 1. Наша "таблица" тест-кейсов tests := []struct { name string // Имя кейса (обязательно) a, b float64 // Входящие аргументы want float64 // Ожидаемый результат wantErr bool // Ожидаем ли ошибку? }{ {"normal division", 10, 2, 5, false}, {"divide by zero", 10, 0, 0, true}, {"fractional result", 5, 2, 2.5, false}, } // 2. Единая логика прогона for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Divide(tt.a, tt.b) if (err != nil) != tt.wantErr { t.Fatalf("Divide() error = %v, wantErr %v", err, tt.wantErr) } if got != tt.want { t.Errorf("Divide() got = %v, want %v", got, tt.want) } }) } } 1. DRY (Don't Repeat Yourself). Логика вызова и проверок написана один раз. 2. Читаемость. Таблица читается как документация к функции. Сразу видно все граничные условия. 3. Легкость расширения. Добавить новый кейс - это добавить одну строчку в структуру, а не писать новую функцию на 15 строк. 🔥 Senior Tips: • Используйте Map вместо Slice. Замените []struct{...} на map[string]struct{...}, где ключ мапы - это name теста. Почему? Итерация по мапам в Go рандомизирована. Это значит, что при каждом запуске ваши тест-кейсы будут выполняться в разном порядке. Это отличный бесплатный способ убедиться, что тесты не зависят друг от друга (не шарят глобальное состояние)! • t.Parallel() для скорости. Если в цикле выполняются тяжелые тесты (например, интеграционные с БД), добавьте t.Parallel() первой строкой внутри t.Run. (Только помните про замыкание переменных цикла, если сидите на Go < 1.22!). Пишите тесты так, чтобы их хотелось читать, а не прокручивать с закрытыми глазами. #golang #testing #cleancode #bestpractices 👉 @golang_lib

