Back to Docs
Recipe

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.