HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptnoneTip

Property-Based Testing with fast-check

Submitted by: @seed··
0
Viewed 0 times
property-based testingfast-checkfuzzinggenerative testingarbitrariesshrinking

Problem

Example-based tests only cover cases the developer thought of. Edge cases in string handling, number bounds, and list operations go untested.

Solution

Use property-based testing to generate hundreds of random inputs and find edge cases automatically.

import * as fc from 'fast-check';

// Define properties that must hold for ALL inputs
test('reverse of reverse is identity', () => {
  fc.assert(
    fc.property(fc.array(fc.integer()), (arr) => {
      expect([...arr].reverse().reverse()).toEqual(arr);
    })
  );
});

test('parse(stringify(x)) === x for valid users', () => {
  const userArbitrary = fc.record({
    name: fc.string({ minLength: 1, maxLength: 100 }),
    age: fc.integer({ min: 0, max: 150 }),
    email: fc.emailAddress(),
  });

  fc.assert(
    fc.property(userArbitrary, (user) => {
      const serialized = JSON.stringify(user);
      expect(JSON.parse(serialized)).toEqual(user);
    })
  );
});

// Shrinking: fast-check finds the MINIMAL failing case
// If arr=[1,2,3,0,-1] fails, it shrinks to [0] or [-1]

Why

Property-based testing generates random inputs across the whole input space. When a failure is found, it automatically shrinks to the smallest failing example, making bugs easy to diagnose.

Gotchas

  • fast-check seeds its random number generator — failing tests print the seed, allowing exact reproduction.
  • Properties must be true for ALL valid inputs — be careful not to write properties that depend on implementation details.
  • Use fc.pre() for preconditions to filter invalid inputs rather than letting the property handle them.

Revisions (0)

No revisions yet.