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
git clone https://github.com/diegosouzapw/awesome-omni-skill
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"
skills/development/property-based-testing-neversight/SKILL.mdProperty-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
| Property | Formula | When to Use |
|---|---|---|
| Roundtrip | | Serialization, conversion pairs |
| Idempotence | | Normalization, formatting, sorting |
| Invariant | Property holds before/after | Any transformation |
| Commutativity | | Binary/set operations |
| Associativity | | Combining operations |
| Identity | | Operations with neutral element |
| Inverse | | encrypt/decrypt, compress/decompress |
| Oracle | | Optimization, refactoring |
| Easy to Verify | | Complex algorithms |
| No Exception | No crash on valid input | Baseline (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:
| Pattern | Property | Priority |
|---|---|---|
/, / | Roundtrip | HIGH |
/, / | Roundtrip | HIGH |
| Pure functions with clear contracts | Multiple | HIGH |
, , | Idempotence | MEDIUM |
, with normalizers | Valid after normalize | MEDIUM |
| Sorting, ordering, comparators | Idempotence + ordering | MEDIUM |
| Custom collections (add/remove/get) | Invariants | MEDIUM |
| Builder/factory patterns | Output invariants | LOW |
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
| Language | Library | Import |
|---|---|---|
| Python | Hypothesis | |
| TypeScript/JS | fast-check | |
| Rust | proptest | |
| Go | rapid | |
| Java | jqwik | annotations |
| Haskell | QuickCheck | |
For library-specific syntax and patterns: Use
@ed3d-research-agents:internet-researcher to get current documentation.
Input Strategy Best Practices
-
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) -
Size limits: Prevent slow tests
st.lists(st.integers(), max_size=100) st.text(max_size=1000) -
Realistic data: Match real-world constraints
st.integers(min_value=0, max_value=150) # Real ages, not arbitrary ints -
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:
tests nothingassert sorted(xs) == sorted(xs) - Only "no crash": Always look for stronger properties
- Vacuous: Multiple
calls filter out most inputsassume() - Reimplementation:
if that's how add is implementedassert add(a, b) == a + b - Missing edge cases: No
,@example([])
decorators@example([1]) - Overly constrained: Many
calls means redesign the strategyassume()
Common Mistakes
| Mistake | Fix |
|---|---|
| Testing mock behavior | Test real behavior |
| Reimplementing function in test | Use algebraic properties |
| Filtering with assume() | Build constraints into strategy |
| No edge case examples | Add @example decorators |
| One property only | Add multiple properties (length, ordering, etc.) |