Skip to main content

Property-Based Testing

advanced11 min readLesson 184 of 204

Instead of example inputs, state the invariant that must hold for ALL inputs โ€” then let generated cases hunt for the violation.

From examples to properties

An example test: sort({3,1,2}) == {1,2,3}. A property: for every vector, sorting yields the same multiset, non-decreasing. One property is worth a hundred examples because it covers the inputs you forgot. Classic C++ properties:

  • Round-trip: parse(serialize(x)) == x (parsers, codecs, string formatting).
  • Involution: compress(decompress(x)) correctness, reverse(reverse(v)) == v.
  • Idempotence: sort(sort(v)) == sort(v), dedup applied twice is applied once.
  • Oracles: compare against a slow-but-obviously-correct implementation.

Random needs structure

Pure random bytes rarely reach interesting code. Generate structured randoms: valid-ish inputs with occasional boundary values (0, 1, INT_MAX, empty). Deterministic seeds keep CI reproducible; the failing case is printed and shrunk to the minimal witness.

Properties as documentation

A property states the contract so precisely that reading the test is reading the spec โ€” "for all n >= 0: buildRange(n).size() == n" teaches the requirement better than prose. The graded exercises here grade property implementations: your checker function must accept correct implementations and reject subtly broken ones.

Now practice

Practice: Round-Trip CodecsBuild both halves of a codec and let the property test hunt for asymmetries.1 challenge ยท ยท ~15 min