Property-based testing with Hypothesis for discovering edge cases automatically. Use when testing invariants, finding boundary conditions, implementing stateful testing, or validating data transformations.
View on GitHubJanuary 24, 2026
Select agents to install to:
npx add-skill https://github.com/yonatangross/orchestkit/blob/main/./skills/property-based-testing/SKILL.md -a claude-code --skill property-based-testingInstallation paths:
.claude/skills/property-based-testing/# Property-Based Testing with Hypothesis
Discover edge cases automatically by testing properties instead of examples.
## Overview
- Testing functions with many possible inputs
- Validating invariants that must hold for all inputs
- Finding boundary conditions and edge cases
- Testing serialization/deserialization roundtrips
- Stateful testing of APIs and state machines
## Quick Reference
### Example-Based vs Property-Based
```python
# Example-based: Test specific inputs
def test_sort_examples():
assert sort([3, 1, 2]) == [1, 2, 3]
# But what about [-1], [1.5, 2.5], ...?
# Property-based: Test properties for ALL inputs
from hypothesis import given
from hypothesis import strategies as st
@given(st.lists(st.integers()))
def test_sort_properties(lst):
result = sort(lst)
assert len(result) == len(lst) # Same length
assert all(result[i] <= result[i+1] for i in range(len(result)-1)) # Ordered
```
See [strategies-guide.md](references/strategies-guide.md) for complete strategy reference.
### Common Strategies
```python
from hypothesis import strategies as st
st.integers(min_value=0, max_value=100) # Bounded integers
st.text(min_size=1, max_size=50) # Bounded text
st.lists(st.integers(), max_size=10) # Bounded lists
st.from_regex(r"[a-z]+@[a-z]+\.[a-z]+") # Pattern-based
# Composite for domain objects
@st.composite
def user_strategy(draw):
return User(
name=draw(st.text(min_size=1, max_size=50)),
age=draw(st.integers(min_value=0, max_value=150)),
)
```
### Common Properties
```python
# Roundtrip (encode/decode)
@given(st.dictionaries(st.text(), st.integers()))
def test_json_roundtrip(data):
assert json.loads(json.dumps(data)) == data
# Idempotence
@given(st.text())
def test_normalize_idempotent(text):
assert normalize(normalize(text)) == normalize(text)
# Oracle (compare to known implementation)
@given(st.lists(st.integers()))
def test_sort_matches_builtin(lst):
assert our_sort(lst) == so