Property-Based Testing Explained

Define properties that should hold for all inputs — and let the testing framework automatically generate hundreds of cases to find the ones that break.

Property-Based Testing

Property-based testing is a testing methodology where tests define properties that should hold for all inputs, and the testing framework automatically generates hundreds of random test cases to verify those properties.

Explanation

Instead of writing specific input-output examples (unit tests), property-based tests describe general rules. For example: "sorting any list should produce a list of the same length with elements in ascending order." The framework generates random lists and verifies the property holds for each. When a failing case is found, the framework automatically shrinks it to the minimal failing example. This catches edge cases that humans miss: empty inputs, very large values, special characters, and boundary conditions. Libraries include fast-check (TypeScript/JavaScript), Hypothesis (Python), QuickCheck (Haskell), and ScalaCheck (Scala).

Bookuvai Implementation

Bookuvai uses property-based testing for algorithmic code, serialization/deserialization, data transformation, and parser implementations. We use fast-check for TypeScript projects, defining invariants that should hold regardless of input. This catches edge cases that example-based tests miss.

Key Facts

  • Tests define properties (invariants) that hold for all inputs
  • Framework generates hundreds of random test cases automatically
  • Automatic shrinking finds the minimal failing example
  • Catches edge cases: empty inputs, boundaries, special characters
  • Libraries: fast-check, Hypothesis, QuickCheck, ScalaCheck

Related Terms

Frequently Asked Questions

When should I use property-based testing vs example-based testing?
Use property-based testing for functions with clear mathematical properties (sorting, encoding/decoding, serialization roundtrips) and when edge cases are hard to enumerate. Use example-based tests for business logic where specific scenarios matter more than general properties.
What is shrinking in property-based testing?
When a random input fails, the framework automatically simplifies it to the smallest input that still fails. A failing list of 1,000 elements might shrink to a list of 2 elements that demonstrates the same bug, making debugging much easier.
Are property-based tests deterministic?
Each run uses a random seed that produces deterministic results for that seed. When a test fails, the seed is logged so you can reproduce the exact same inputs. Most frameworks also support fixed seeds for CI determinism.