Property‑Based Testing
Replace hand‑written examples with invariants that hold for every input. The computer finds the counterexamples you missed.
The Core Idea
Instead of asserting f(2) == 4, you declare a property like “sorting a list twice gives the same result as sorting once” and let the framework generate hundreds of random inputs.
When to Reach for It
- •Round‑trip properties: encode then decode returns the original.
- •Idempotence: running an operation twice changes nothing the second time.
- •Model‑based: compare a simple reference implementation against the real one.
- •Hard‑to‑reverse logic: parsers, serializers, compression, cryptography.
Shrinking
When a property fails, the framework shrinks the input to the smallest possible counterexample. A 10,000‑element list that breaks your sort becomes [2, 1]. You debug the essence, not the noise.
Tooling
TypeScript: fast‑check. Python: Hypothesis. Rust: proptest. Go: rapid or gotest fuzzing. All follow the same pattern: define a generator, write a property, let it run.
Pro Tip
Start with the inverse property. If you have a serializer, the first test is always “deserialize(serialize(x)) == x”. It catches more bugs than any hand‑written fixture ever will.