🌪 Fuzzing: Ломаем свой код, пока это не сделали другие Мы привыкли писать Unit-тесты по принципу: "Я ожидаю, что если подать А, выйдет Б".
Мы привыкли писать Unit-тесты по принципу: "Я ожидаю, что если подать А, выйдет Б".
Но проблема Unit-тестов в том, что они ограничены вашей фантазией. Вы тестируете только те кейсы, которые смогли придумать.
А что будет, если подать пустую строку? А если строку из 10 МБ эмодзи? А если битый JSON?
Тут на сцену выходит Fuzzing (Фаззинг).
Начиная с Go 1.18, он встроен прямо в go test.
Как это работает?
Фаззер - это бесконечная обезьяна, которая лупит по клавиатуре, пытаясь сломать вашу функцию. Но обезьяна умная.
1. Она берет ваши примеры (seed corpus).
2. Немного их меняет (мутирует биты, обрезает, дублирует).
3. Следит за покрытием кода (code coverage).
4. Если новый ввод зашел в новую ветку if, фаззер запоминает этот ввод и начинает мутировать уже его.
Цель фаззера - найти такие данные, которые вызовут panic, бесконечный цикл или съедят всю память.
Пример:
Допустим, у нас есть "безопасная" функция деления:
func SafeDiv(a, b int) int {
if b == 0 {
return 0 // Защита от паники?
}
return a / b
}
Пишем фазз-тест:
func FuzzSafeDiv(f *testing.F) {
// 1. Seed Corpus: даем примеры валидных данных
f.Add(10, 2)
f.Add(100, 5)
// 2. Fuzz Loop: запускаем хаос
f.Fuzz(func(t *testing.T, a int, b int) {
// Вызываем нашу функцию
// Если она запаникует — тест упадет
SafeDiv(a, b)
})
}
Запускаем: go test -fuzz=Fuzz
И через секунду фаззер найдет баг, о котором забывают 90% джунов (и 30% сеньоров).
При вводе SafeDiv(-9223372036854775808, -1) (MinInt64 / -1) программа упадет с переполнением, потому что результат не влезает в int64. Unit-тест вы бы такой в жизни не написали.
🔥 Senior Tip: Property-based Testing
Фаззинг нужен не только, чтобы искать паники. Он идеален для проверки инвариантов.
Например, если вы написали свой кодек или шифрование:
f.Fuzz(func(t *testing.T, original []byte) {
encoded := Encode(original)
decoded := Decode(encoded)
if !bytes.Equal(original, decoded) {
t.Fatalf("Данные повредились: %v -> %v", original, decoded)
}
})
Это найдет баги в пограничных случаях (например, когда байт равен 0x00 или 0xFF).
#golang #testing #fuzzing #security #quality
👉 @golang_lib