Fuzzing and Property-Style Tests

Updated

September 8, 2026

Fuzzing and Property-Style Tests

Overview

Fuzzing feeds random inputs to find panics and logic bugs. Go’s built-in fuzzing (go test -fuzz) is ideal for parsers, validators, and codecs.

Fuzz target

func FuzzParsePort(f *testing.F) {
    f.Add("8080")
    f.Add("0")
    f.Add("65535")
    f.Fuzz(func(t *testing.T, s string) {
        n, err := strconv.Atoi(s)
        if err != nil {
            return
        }
        if n < 0 {
            t.Fatalf("negative: %d", n)
        }
        // property: round-trip for valid ports
        if n >= 0 && n <= 65535 {
            if strconv.Itoa(n) != s && !strings.HasPrefix(s, "0") && s != "0" {
                // allow leading zeros mismatch — define your contract
            }
        }
    })
}
go test -fuzz=FuzzParsePort -fuzztime=10s

Seed corpus

f.Add seeds interesting cases; failing inputs land in testdata/fuzz/.

Good fuzz targets

Good Poor
JSON/decode, path clean, URL parse wrappers Tests needing full DB
Pure functions Non-deterministic time without injection

Property ideas

  • Round-trip: decode(encode(x)) == x
  • Idempotent clean: clean(clean(p)) == clean(p)
  • Never panics on any byte slice

Rules of thumb

Do Don’t
Fix corpus failures as tests Delete corpus to “go green”
Bound work in fuzz body Sleep/network in fuzz
Run in CI with -fuzztime short Only fuzz manually once

Try next

  1. Fuzz your safeJoin — should never escape root.
  2. Fuzz JSON validator.
  3. Commit a minimized failing corpus once fixed.