В Go тестирование встроено в инструменты: никаких фреймворков ставить не нужно. И зависимости тоже управляются самим go.
Тесты
Файл xxx_test.go, функция TestXxx(t *testing.T), запуск go test ./....
func TestAbs(t *testing.T) {
tests := []struct {
name string
in int
want int
}{
{"положительное", 3, 3},
{"отрицательное", -3, 3},
{"ноль", 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
if got := Abs(tt.in); got != tt.want {
t.Errorf("Abs(%d) = %d, want %d", tt.in, got, tt.want)
}
})
}
}
- Табличные тесты: стандартный стиль Go.
t.Errorfотмечает провал и продолжает,t.Fatalfостанавливает текущий тест.t.Runсоздаёт подтест, запуск одного:go test -run 'TestAbs/ноль'.t.Parallel()запускает подтесты параллельно. С Go 1.22 захватttв цикле больше не баг.t.Helper()в хелперах, чтобы в ошибке была строка вызова.t.Cleanupдля уборки,t.TempDir()для временной папки,t.Setenvдля переменных окружения.TestMain(m *testing.M)для общей подготовки пакета.- Кеш: повторный
go testберёт результат из кеша, если ничего не изменилось. Сбросить:-count=1.
Моки
Mock в Go обычно делают через интерфейс, объявленный у потребителя:
type UserStore interface { Get(ctx context.Context, id int) (User, error) }
type fakeStore struct{ u User }
func (f fakeStore) Get(context.Context, int) (User, error) { return f.u, nil }
Генераторы моков: go.uber.org/mock (mockgen), mockery. Для HTTP есть httptest.NewRecorder и httptest.NewServer. Для интеграции с базой часто берут testcontainers.
Покрытие и race
go test -cover, -coverprofile=c.out и go tool cover -html=c.out. go test -race обязательно в CI для конкурентного кода.
Бенчмарки
func BenchmarkJoin(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = strings.Join(parts, ",")
}
}
Запуск go test -bench=. -benchmem: время на операцию, байты и число аллокаций на операцию. b.N подбирает фреймворк. С Go 1.24 удобнее for b.Loop() { ... }: подготовка до цикла не попадает в замер, а результат не выкидывается оптимизатором. Сравнивать результаты до и после правки: benchstat.
Fuzzing
С Go 1.18: func FuzzParse(f *testing.F), f.Add(seed), f.Fuzz(func(t *testing.T, s string) {...}). Запуск go test -fuzz=FuzzParse. Найденные падения сохраняются в testdata/fuzz и потом работают как обычные тесты.
Примеры
func ExampleAbs() с комментарием // Output: 3 это и документация, и тест.
Модули
module github.com/acme/shop
go 1.24
require (
github.com/jackc/pgx/v5 v5.7.1
golang.org/x/sync v0.10.0
)
go mod init,go get pkg@v1.2.3,go mod tidy(добавить нужное и убрать лишнее).go.sumхранит хеши содержимого модулей, его коммитят. Проверка идёт ещё и через публичную базуsum.golang.org.- Семантическое версионирование. Мажорная версия 2 и выше входит в путь импорта:
.../v2. Это разные модули. - MVS (minimal version selection): из всех требований к модулю выбирается максимальная из минимально требуемых версий, а не самая свежая. Сборка воспроизводима без lock-файла.
- Директива
goзадаёт версию языка (и, например, семантику переменной цикла),toolchainподсказывает версию инструментов. С Go 1.21goскачивает нужный тулчейн сам. replaceдля локальной разработки,go.workдля нескольких модулей в одном репо.- Приватные модули:
GOPRIVATE=github.com/acme/*, прокси по умолчаниюproxy.golang.org. - Директория
internal/закрывает пакеты от импорта извне родителя. - С Go 1.24 в
go.modесть директиваtoolдля утилит разработки.
Что спросят на собесе
- Как писать табличные тесты и подтесты.
- Как мокать зависимости в Go.
- Как написать бенчмарк и что показывает
-benchmem. - Что такое MVS и зачем
go.sum. - Как устроены мажорные версии модулей и что делает
go mod tidy.