Run tests with fuzzing to generate new inputs:
go test -fuzz=Fuzz
Or with a timeout:
go test -fuzz=Fuzz -fuzztime 30s
Here's an example fuzz test that is meant to test a function which reverses a string:
func FuzzReverse(f *testing.F) {
testcases := []string{"Hello, world", " ", "!12345"}
for _, tc := range testcases {
f.Add(tc) // Use f.Add to provide a seed corpus
}
f.Fuzz(func(t *testing.T, orig string) {
rev := Reverse(orig)
doubleRev := Reverse(rev)
if orig != doubleRev {
t.Errorf("Before: %q, after: %q", orig, doubleRev)
}
if utf8.ValidString(orig) && !utf8.ValidString(rev) {
t.Errorf("Reverse produced invalid UTF-8 string %q", rev)
}
})
}
It has three seed inputs and it works by reversing the input twice and seeing if it produces the original value. It also ensures the output is valid UTF-8 if the input was valid.
If the implementation of Reverse cannot handle unicode runes properly (for example it loops over bytes), this fuzz test will quickly find the error and show something like this:
$ go test -fuzz=Fuzz
fuzz: elapsed: 0s, gathering baseline coverage: 0/3 completed
fuzz: elapsed: 0s, gathering baseline coverage: 3/3 completed, now fuzzing with 4 workers
fuzz: elapsed: 0s, execs: 895 (21571/sec), new interesting: 6 (total: 9)
--- FAIL: FuzzReverse (0.04s)
--- FAIL: FuzzReverse (0.00s)
main_test.go:20: Reverse produced invalid UTF-8 string "\xaf\xd8"
Failing input written to testdata/fuzz/FuzzReverse/0229db533095672568a403ab07a0c32685fe85c776b5a3be9755fe4e91e02020
To re-run:
go test -run=FuzzReverse/0229db533095672568a403ab07a0c32685fe85c776b5a3be9755fe4e91e02020
FAIL
exit status 1
FAIL git.sr.ht/~kota/learn/go/fuzz/tutorial 0.045s
It will create a file in ./testdata/fuzz/..
containing something like:
go test fuzz v1
string("د")