💻 Tech
Go fuzz testing is a type of testing that generates random data to test a function. This is helpful if you want to uncover edge cases and vulnerabilities that may not be apparent with your existing unit tests.
The example code below tests testString function, which deliberately throws an error once the maximum number of vowels is reached. f.Fuzz generates random string given that a string type is provided in the function signature. By running go test -fuzz ., you can perform fuzz testing.
When the test fails, Go saves the last input data and reuses it for the next testing. Note that this runs indefinitely until the test fails or you stop it. To provide a time limit, you can use this the -fuzztime argument: go test -fuzz . -fuzztime 10s -v .
main.go
func testString(text string) error {
vowels := map[string]bool{"a": true, "e": true, "i": true, "o": true, "u": true}
maxVowel := 1000
ctr := 0
for _, r := range text {
if ok := vowels[string(r)]; ok {
ctr++
}
if ctr > maxVowel {
return fmt.Errorf("max vowel reached")
}
}
return nil
}
main_test.go
func FuzzTestString(f *testing.F) {
f.Fuzz(func(t *testing.T, text string) {
if err := testString(text); err != nil {
t.Fatal(err)
}
})
}
output:
go test -fuzz .
fuzz: elapsed: 0s, gathering baseline coverage: 0/10 completed
fuzz: elapsed: 0s, gathering baseline coverage: 10/10 completed, now fuzzing with 12 workers
fuzz: minimizing 2908-byte failing input file
fuzz: elapsed: 3s, minimizing
fuzz: elapsed: 6s, minimizing
fuzz: elapsed: 9s, minimizing
fuzz: elapsed: 12s, minimizing
fuzz: elapsed: 15s, minimizing
fuzz: elapsed: 18s, minimizing
fuzz: elapsed: 20s, minimizing
--- FAIL: FuzzTestString (19.95s)
--- FAIL: FuzzTestString (0.00s)
main_test.go:10: max vowel reached
Failing input written to testdata/fuzz/FuzzTestString/2beb4d213f46e78d
To re-run:
go test -run=FuzzTestString/2beb4d213f46e78d
FAIL
exit status 1
FAIL fuzz 19.956s