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 GitHubyonatangross/orchestkit
ork-testing-core
January 25, 2026
Select agents to install to:
npx add-skill https://github.com/yonatangross/orchestkit/blob/main/plugins/ork-testing-core/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