Fuzzing
Тема дорожной карты · Golang
Фаззинг в Go — техника тестирования, при которой Go-тулчейн автоматически генерирует случайные и мутированные входные данные для поиска паник, некорректного вывода или уязвимостей безопасности, которые пропускают рукописные тест-кейсы. Нативный фаззинг в Go появился в версии 1.18 как часть стандартного пакета testing: фаззинг-тест объявляется с сигнатурой func FuzzXxx(f *testing.F), начальные записи корпуса добавляются через f.Add(...), а фаззинг-движок запускается командой go test -fuzz=FuzzXxx. Фаззер инструментирует бинарник для coverage-guided мутации, изменяя входные данные, которые увеличивают покрытие кода, — гораздо более тщательный подход, чем чисто случайный фаззинг. Фаззинг в Go особенно ценен для парсеров, декодеров, криптографических процедур и любого кода, обрабатывающего недоверенные внешние данные; он был использован для нахождения реальных ошибок в самой стандартной библиотеке Go. Найденные сбойные входные данные сохраняются в testdata/fuzz/FuzzXxx/ и воспроизводятся как регрессионные тесты при каждом будущем запуске go test, делая фаззинг постоянной страховкой в тестовом рабочем процессе Go.
Как это работает
Fuzzing использует stdlib testing-пакет — фреймворк не нужен. Файлы заканчиваются на _test.go; тесты — func TestX(t *testing.T); subtests через t.Run. Table-driven тесты — идиоматический паттерн. Бенчмарки: func BenchmarkX(b *testing.B), запуск go test -bench=.. Моки: опирайтесь на маленькие интерфейсы (Go-интерфейсы duck-typed — легко заменить stub); gomock или mockery — для генерируемых моков. testify — для fluent-ассертов, httptest — для тестов HTTP-handlers.
Когда применять
Table-driven тесты — дефолт: читаемы, легко добавить кейсы. httptest.Server — для тестов HTTP-клиентов; httptest.ResponseRecorder — для тестов handlers. В CI — с -race. testify — если команда предпочитает fluent-ассерты; иначе stdlib t.Errorf достаточен. dockertest или testcontainers-go — для тестов с реальной БД.
Типичные ошибки
Ловушки Fuzzing: параллельные тесты (t.Parallel()), делящие state (тонкие race conditions); бенчмарки, оптимизируемые компилятором (присваивайте результаты пакетной sink-переменной); нет -race в CI (data race проскакивают в production); over-mocking — тесты проверяют детали реализации, не поведение.