Back to list
ed3dai

property-based-testing

by ed3dai

Ed's repo of Claude Code plugins, centered around a research-plan-implement workflow. Only a tiny bit cursed. If you're lucky.

72🍴 3📅 Jan 23, 2026

SKILL.md


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

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
Roundtripdecode(encode(x)) == xSerialization, conversion pairs
Idempotencef(f(x)) == f(x)Normalization, formatting, sorting
InvariantProperty holds before/afterAny transformation
Commutativityf(a, b) == f(b, a)Binary/set operations
Associativityf(f(a,b), c) == f(a, f(b,c))Combining operations
Identityf(x, identity) == xOperations with neutral element
Inversef(g(x)) == xencrypt/decrypt, compress/decompress
Oraclenew_impl(x) == reference(x)Optimization, refactoring
Easy to Verifyis_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/deserializeRoundtripHIGH
toJSON/fromJSON, pack/unpackRoundtripHIGH
Pure functions with clear contractsMultipleHIGH
normalize, sanitize, canonicalizeIdempotenceMEDIUM
is_valid, validate with normalizersValid 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
PythonHypothesisfrom hypothesis import given, strategies as st
TypeScript/JSfast-checkimport fc from 'fast-check'
Rustproptestuse proptest::prelude::*
Gorapidimport "pgregory.net/rapid"
Javajqwik@Property annotations
HaskellQuickCheckimport 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.)

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon