Awesome-omni-skill property-based-testing

Use when writing tests for serialization, validation, normalization, or pure functions - provides property catalog, pattern detection, and library reference for property-based testing

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/property-based-testing-neversight" ~/.claude/skills/diegosouzapw-awesome-omni-skill-property-based-testing-71d8f2 && rm -rf "$T"
manifest: skills/development/property-based-testing-neversight/SKILL.md
source content

Property-Based Testing

Overview

Property-based testing (PBT) generates random inputs and verifies that properties hold for all of them. Instead of testing specific examples, you test invariants.

When PBT beats example-based tests:

  • Serialization pairs (encode/decode)
  • Pure functions with clear contracts
  • Validators and normalizers
  • Data structure operations

Property Catalog

PropertyFormulaWhen to Use
Roundtrip
decode(encode(x)) == x
Serialization, conversion pairs
Idempotence
f(f(x)) == f(x)
Normalization, formatting, sorting
InvariantProperty holds before/afterAny transformation
Commutativity
f(a, b) == f(b, a)
Binary/set operations
Associativity
f(f(a,b), c) == f(a, f(b,c))
Combining operations
Identity
f(x, identity) == x
Operations with neutral element
Inverse
f(g(x)) == x
encrypt/decrypt, compress/decompress
Oracle
new_impl(x) == reference(x)
Optimization, refactoring
Easy to Verify
is_sorted(sort(x))
Complex algorithms
No ExceptionNo crash on valid inputBaseline (weakest)

Strength hierarchy (weakest to strongest):

No Exception -> Type Preservation -> Invariant -> Idempotence -> Roundtrip

Always aim for the strongest property that applies.

Pattern Detection

Use PBT when you see:

PatternPropertyPriority
encode
/
decode
,
serialize
/
deserialize
RoundtripHIGH
toJSON
/
fromJSON
,
pack
/
unpack
RoundtripHIGH
Pure functions with clear contractsMultipleHIGH
normalize
,
sanitize
,
canonicalize
IdempotenceMEDIUM
is_valid
,
validate
with normalizers
Valid after normalizeMEDIUM
Sorting, ordering, comparatorsIdempotence + orderingMEDIUM
Custom collections (add/remove/get)InvariantsMEDIUM
Builder/factory patternsOutput invariantsLOW

When NOT to Use

  • Simple CRUD without transformation logic
  • UI/presentation logic
  • Integration tests requiring complex external setup
  • Code with side effects that cannot be isolated
  • Prototyping where requirements are fluid
  • Tests where specific examples suffice and edge cases are understood

Library Quick Reference

LanguageLibraryImport
PythonHypothesis
from hypothesis import given, strategies as st
TypeScript/JSfast-check
import fc from 'fast-check'
Rustproptest
use proptest::prelude::*
Gorapid
import "pgregory.net/rapid"
Javajqwik
@Property
annotations
HaskellQuickCheck
import Test.QuickCheck

For library-specific syntax and patterns: Use

@ed3d-research-agents:internet-researcher
to get current documentation.

Input Strategy Best Practices

  1. Constrain early: Build constraints INTO the strategy, not via

    assume()

    # GOOD
    st.integers(min_value=1, max_value=100)
    
    # BAD - high rejection rate
    st.integers().filter(lambda x: 1 <= x <= 100)
    
  2. Size limits: Prevent slow tests

    st.lists(st.integers(), max_size=100)
    st.text(max_size=1000)
    
  3. Realistic data: Match real-world constraints

    st.integers(min_value=0, max_value=150)  # Real ages, not arbitrary ints
    
  4. Reuse strategies: Define once, use across tests

    valid_users = st.builds(User, ...)
    
    @given(valid_users)
    def test_one(user): ...
    
    @given(valid_users)
    def test_two(user): ...
    

Settings Guide

# Development (fast feedback)
@settings(max_examples=10)

# CI (thorough)
@settings(max_examples=200)

# Nightly/Release (exhaustive)
@settings(max_examples=1000, deadline=None)

Quality Checklist

Before committing PBT tests:

  • Not tautological (assertion doesn't compare same expression)
  • Strong assertion (not just "no crash")
  • Not vacuous (inputs not over-filtered by
    assume()
    )
  • Edge cases covered with explicit examples (
    @example
    )
  • No reimplementation of function logic in assertion
  • Strategy constraints are realistic
  • Settings appropriate for context

Red Flags

  • Tautological:
    assert sorted(xs) == sorted(xs)
    tests nothing
  • Only "no crash": Always look for stronger properties
  • Vacuous: Multiple
    assume()
    calls filter out most inputs
  • Reimplementation:
    assert add(a, b) == a + b
    if that's how add is implemented
  • Missing edge cases: No
    @example([])
    ,
    @example([1])
    decorators
  • Overly constrained: Many
    assume()
    calls means redesign the strategy

Common Mistakes

MistakeFix
Testing mock behaviorTest real behavior
Reimplementing function in testUse algebraic properties
Filtering with assume()Build constraints into strategy
No edge case examplesAdd @example decorators
One property onlyAdd multiple properties (length, ordering, etc.)