patterntypescriptnoneTip
Property-Based Testing with fast-check
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.