Функция FuzzXxx
Функция FuzzXxx используется в пакете testing для создания фаззинг-тестов.
Она принимает указатель на тип testing.F и выполняет тестирование с генерацией случайных данных.
Фаззинг-тесты помогают обнаружить ошибки, которые сложно найти с помощью обычных тестов, такие как паника,
выход за границы массива или некорректная обработка краевых случаев.
Синтаксис
func FuzzXxx(f *testing.F) {
// Добавление seed-корпусов
f.Add(initialInput)
// Определение фаззинг-функции
f.Fuzz(func(t *testing.T, input ...interface{}) {
// Тестируемый код с случайными входными данными
})
}
Функция FuzzXxx должна принимать один параметр - указатель на testing.F.
Внутри функции с помощью метода Add можно добавлять начальные значения (seed-корпусы),
которые будут использоваться для генерации случайных данных. Метод Fuzz определяет
фаззинг-функцию, которая принимает testing.T и список входных параметров.
Пример
Давайте создадим фаззинг-тест для функции, которая преобразует строку в целое число:
package main
import (
"strconv"
"testing"
)
func FuzzParseInt(f *testing.F) {
// Добавляем начальные значения для генерации
f.Add("123")
f.Add("0")
f.Add("-456")
f.Fuzz(func(t *testing.T, input string) {
result, err := strconv.Atoi(input)
if err != nil {
// Для ошибок просто пропускаем
t.Skip()
}
// Проверяем, что результат преобразуется обратно
if strconv.Itoa(result) != input && input[0] != '+' {
t.Errorf("Atoi и Itoa не обратны для %s", input)
}
})
}
Результат выполнения команды для запуска фаззинг-теста:
"go test -fuzz=FuzzParseInt"
Пример
Рассмотрим фаззинг-тест для функции, которая работает с числами с плавающей точкой:
package main
import (
"math"
"testing"
)
func FuzzSqrt(f *testing.F) {
// Добавляем seed-корпусы
f.Add(4.0)
f.Add(0.0)
f.Add(1.0)
f.Fuzz(func(t *testing.T, x float64) {
// Избегаем NaN и Inf
if math.IsNaN(x) || math.IsInf(x, 0) {
t.Skip()
}
// Вычисляем квадратный корень
result := math.Sqrt(x)
// Проверяем, что результат не NaN
if math.IsNaN(result) {
t.Errorf("Sqrt(%f) вернул NaN", x)
}
// Проверяем, что sqrt(x) >= 0 для x >= 0
if x >= 0 && result < 0 {
t.Errorf("Sqrt(%f) = %f, ожидается >= 0", x, result)
}
})
}
Результат выполнения кода:
"fuzz: elapsed: 0s, execs: 1000 (1000/sec), new interesting: 2"
Пример
Фаззинг-тест для функции, которая работает со слайсами байт:
package main
import (
"bytes"
"testing"
)
func FuzzReverse(f *testing.F) {
// Добавляем начальные данные
f.Add([]byte("hello"))
f.Add([]byte("12345"))
f.Add([]byte{})
f.Fuzz(func(t *testing.T, data []byte) {
// Проверяем, что реверс работает корректно
original := make([]byte, len(data))
copy(original, data)
// Реверсируем слайс
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
// Проверяем, что после двойного реверса получаем исходные данные
for i, j := 0, len(data)-1; i < j; i, j = i+1, j-1 {
data[i], data[j] = data[j], data[i]
}
if !bytes.Equal(data, original) {
t.Errorf("Двойной реверс не вернул исходные данные")
}
})
}
Результат выполнения кода:
"ok example 0.234s"
Смотрите также
-
функцию
testing.F,
которая представляет собой фаззинг-контекст -
метод
testing.F.Add,
который добавляет seed-корпусы для фаззинг-теста -
метод
testing.F.Fuzz,
который определяет фаззинг-функцию -
тип
testing.T,
который используется в фаззинг-функции для управления тестированием