# Тестирование в Go

> Встроенная система тестирования Go — пакет testing и команда go test — с табличными тестами, подтестами, бенчмарками, фаззингом, покрытием и детектором гонок без сторонних фреймворков.

Источник: https://llmdocs.ru/wiki/go-testing/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Язык**: Go
- **Инструменты**: пакет testing, команда go test
- **Файлы тестов**: *_test.go
- **Виды**: тесты (TestXxx), бенчмарки (BenchmarkXxx), фаззинг (FuzzXxx), примеры (ExampleXxx)
- **Покрытие**: go test -cover, -coverprofile
- **Гонки**: go test -race
**Тестирование в Go** встроено в сам инструментарий языка: пакет `testing` из [стандартной библиотеки](https://llmdocs.ru/wiki/go-stdlib.md) и команда `go test` поддерживают модульные тесты, бенчмарки, фаззинг, проверяемые примеры, покрытие кода и поиск гонок данных. В отличие от многих языков, для этого не нужен сторонний фреймворк — хотя библиотеки-помощники вроде testify популярны.[1][2]

## Основы

Тесты лежат рядом с кодом в файлах с суффиксом `_test.go` и не попадают в итоговый бинарник. Тестовая функция называется `TestXxx` и принимает `*testing.T`:

```go
// mathx/abs.go
package mathx

func Abs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}
```

```go
// mathx/abs_test.go
package mathx

import "testing"

func TestAbs(t *testing.T) {
    if got := Abs(-3); got != 3 {
        t.Errorf("Abs(-3) = %d, want 3", got)
    }
}
```

```bash
go test ./...                 # все пакеты модуля
go test -run TestAbs -v ./mathx
go test -count=1 ./...        # без кэша результатов
```

`t.Errorf` отмечает ошибку и продолжает выполнение, `t.Fatalf` — останавливает тест. Встроенных функций-«ассертов» нет намеренно: проверки пишутся обычным `if`, а сообщение принято строить в форме «got X, want Y».

## Табличные тесты и подтесты

Идиоматический стиль Go — **табличные тесты**: набор случаев описывается срезом структур, а одна петля их проверяет.[3] Каждый случай запускается как **подтест** через `t.Run`, что даёт отдельное имя, возможность запустить один случай и параллельность:[5]

```go
func TestAbsTable(t *testing.T) {
    tests := []struct {
        name string
        in   int
        want int
    }{
        {"positive", 5, 5},
        {"negative", -5, 5},
        {"zero", 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 test -run 'TestAbsTable/negative'` запустит только один случай. С Go 1.22 переменная цикла создаётся заново на каждой итерации, поэтому старый приём `tt := tt` больше не нужен.

## Полезные возможности testing.T

- `t.Helper()` — помечает вспомогательную функцию, чтобы ошибка указывала на строку вызывающего теста;
- `t.Cleanup(func(){...})` — освобождение ресурсов после теста;
- `t.TempDir()` — временный каталог, удаляемый автоматически;
- `t.Setenv("KEY", "v")` — временная [переменная окружения](https://llmdocs.ru/wiki/environment-variables.md);
- `t.Skip()` и флаг `-short` — пропуск медленных тестов;
- `TestMain(m *testing.M)` — общая подготовка и завершение для пакета.

## Бенчмарки

Функции `BenchmarkXxx(b *testing.B)` измеряют производительность. С Go 1.24 рекомендуемая форма — цикл `b.Loop()`, который сам управляет числом итераций и не даёт компилятору выбросить измеряемый код:[7]

```go
func BenchmarkAbs(b *testing.B) {
    for b.Loop() {
        Abs(-42)
    }
}
```

```bash
go test -bench=. -benchmem ./mathx
```

Для сравнения результатов до и после изменения используют утилиту `benchstat`, которая учитывает статистический разброс; профили для `pprof` получают флагами `-cpuprofile` и `-memprofile`.

## Фаззинг

С Go 1.18 фаззинг встроен в `go test`.[4] Фазз-тест получает случайно мутируемые входные данные и ищет паники или нарушения свойств; найденные «падающие» входы сохраняются в `testdata/fuzz` и становятся регрессионными тестами:

```go
func FuzzReverse(f *testing.F) {
    f.Add("hello")
    f.Fuzz(func(t *testing.T, s string) {
        if Reverse(Reverse(s)) != s {
            t.Errorf("double reverse mismatch for %q", s)
        }
    })
}
```

```bash
go test -fuzz=FuzzReverse -fuzztime=30s
```

## Примеры

Функции `ExampleXxx` с комментарием `// Output:` одновременно служат документацией на pkg.go.dev и тестом: `go test` сравнивает вывод с ожидаемым.

## HTTP и внешние зависимости

Пакет `net/http/httptest` позволяет тестировать обработчики без сети — через `httptest.NewRecorder` — или поднять настоящий тестовый сервер на случайном порту через `httptest.NewServer`.[6] Зависимости от баз и внешних API в Go обычно заменяют через небольшие интерфейсы и собственные фейковые реализации; для интеграционных тестов с настоящей [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) популярен testcontainers-go, поднимающий контейнеры [Docker](https://llmdocs.ru/wiki/docker.md).

## Покрытие и гонки

```bash
go test -cover ./...
go test -coverprofile=cover.out ./... && go tool cover -html=cover.out
go test -race ./...
```

Флаг `-race` включает детектор гонок данных, который находит одновременный доступ к памяти из разных [горутин](https://llmdocs.ru/wiki/goroutines-channels.md) без синхронизации (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). В [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) тесты обычно запускают с `-race` вместе с [go vet](https://llmdocs.ru/wiki/gofmt-govet.md) — последний и так частично выполняется при `go test`.

## Библиотеки

Стандартных средств хватает большинству проектов, но популярны: **testify** (`assert`, `require`, моки), **go-cmp** (`cmp.Diff` для наглядного сравнения структур), **gomock** и **mockery** (генерация моков), **Ginkgo/Gomega** (BDD-стиль). В Python похожую роль играет [pytest](https://llmdocs.ru/wiki/pytest.md).

## См. также

- [Go (язык)](https://llmdocs.ru/wiki/go.md)
- [gofmt и go vet](https://llmdocs.ru/wiki/gofmt-govet.md)
- [pytest](https://llmdocs.ru/wiki/pytest.md)
- [CI/CD](https://llmdocs.ru/wiki/ci-cd.md)

## Источники

1. [Go — package testing](https://pkg.go.dev/testing)
2. [Go — Command go: Test packages](https://pkg.go.dev/cmd/go#hdr-Test_packages)
3. [Go Wiki — TableDrivenTests](https://go.dev/wiki/TableDrivenTests)
4. [Go — Tutorial: Getting started with fuzzing](https://go.dev/doc/tutorial/fuzz)
5. [Go Blog — Using Subtests and Sub-benchmarks](https://go.dev/blog/subtests)
6. [Go — package net/http/httptest](https://pkg.go.dev/net/http/httptest)
7. [Go Blog — More predictable benchmarking with testing.B.Loop](https://go.dev/blog/testing-b-loop)
