Skip to content
hypothesis-strategies logo

Hypothesis strategies

hypothesis-strategies

Custom Hypothesis strategy patterns for property-based testing. Activated when designing test data generators or property tests.

SKILL.md

Full skill instructions

Hypothesis strategies

Purpose

Guide for designing custom Hypothesis strategies for property-based testing. Covers strategy composition, custom generators, and shrinking behavior.

When to use

This skill activates when:

  • Creating custom data generators
  • Composing complex test inputs
  • Designing property-based tests
  • Debugging shrinking behavior
  • Generating domain-specific data

Core concepts

Basic strategies

from hypothesis import strategies as st

# Basic types
text = st.text()
integers = st.integers()
floats = st.floats()
booleans = st.booleans()

# Constrained types
positive_ints = st.integers(min_value=1)
short_text = st.text(max_size=100)
ascii_text = st.text(alphabet=string.ascii_letters)

Strategy composition

from hypothesis import strategies as st

# Combine strategies
point = st.tuples(st.floats(), st.floats())
person = st.fixed_dictionaries({
    'name': st.text(min_size=1),
    'age': st.integers(min_value=0, max_value=150),
})

# One of multiple options
value = st.one_of(st.text(), st.integers(), st.booleans())

# Optional values
maybe_text = st.text() | st.none()

Custom strategies

Using @composite

from hypothesis import strategies as st
from hypothesis.strategies import composite, DrawFn

@composite
def valid_identifiers(draw: DrawFn) -> str:
    """Generate valid Python identifiers."""
    first = draw(st.sampled_from(string.ascii_letters + '_'))
    rest = draw(st.text(
        alphabet=string.ascii_letters + string.digits + '_',
        max_size=30
    ))
    return first + rest

@composite
def valid_emails(draw: DrawFn) -> str:
    """Generate valid email addresses."""
    local = draw(st.text(
        alphabet=string.ascii_lowercase + string.digits + '._',
        min_size=1,
        max_size=64,
    ))
    domain = draw(st.text(
        alphabet=string.ascii_lowercase,
        min_size=1,
        max_size=20,
    ))
    tld = draw(st.sampled_from(['com', 'org', 'net', 'io']))
    return f"{local}@{domain}.{tld}"

Building from existing strategies

@composite
def config_dicts(draw: DrawFn) -> dict:
    """Generate valid configuration dictionaries."""
    name = draw(valid_identifiers())
    options = draw(st.lists(st.text(), max_size=10))
    enabled = draw(st.booleans())
    timeout = draw(st.integers(min_value=1, max_value=3600) | st.none())

    config = {
        'name': name,
        'options': options,
        'enabled': enabled,
    }

    if timeout is not None:
        config['timeout'] = timeout

    return config

Recursive strategies

@composite
def nested_dicts(draw: DrawFn, max_depth: int = 3) -> dict:
    """Generate nested dictionary structures."""
    if max_depth <= 0:
        # Base case: simple values only
        return draw(st.fixed_dictionaries({
            'value': st.one_of(st.text(), st.integers(), st.booleans())
        }))

    # Recursive case
    return draw(st.fixed_dictionaries({
        'value': st.one_of(st.text(), st.integers(), st.booleans()),
        'children': st.lists(
            st.deferred(lambda: nested_dicts(max_depth=max_depth - 1)),
            max_size=3
        )
    }))

Strategy for domain types

Dataclass strategies

from dataclasses import dataclass
from hypothesis import strategies as st

@dataclass
class User:
    id: int
    name: str
    email: str
    active: bool

@composite
def users(draw: DrawFn) -> User:
    """Generate valid User instances."""
    return User(
        id=draw(st.integers(min_value=1)),
        name=draw(st.text(min_size=1, max_size=100)),
        email=draw(valid_emails()),
        active=draw(st.booleans()),
    )

Enum strategies

from enum import Enum

class Status(Enum):
    PENDING = 'pending'
    ACTIVE = 'active'
    COMPLETED = 'completed'

# Generate any status
status_strategy = st.sampled_from(Status)

# Generate only certain statuses
active_statuses = st.sampled_from([Status.PENDING, Status.ACTIVE])

Using with @given

Basic usage

from hypothesis import given

@given(users())
def test_user_has_valid_id(user: User):
    """User IDs are always positive."""
    assert user.id > 0

@given(st.lists(users(), min_size=1))
def test_user_list_not_empty(users: list[User]):
    """Generated user lists have at least one user."""
    assert len(users) >= 1

With assume

from hypothesis import given, assume

@given(st.integers(), st.integers())
def test_division(a: int, b: int):
    """Test division with valid divisor."""
    assume(b != 0)
    result = a / b
    assert result * b == a

Multiple strategies

@given(
    user=users(),
    permissions=st.lists(st.sampled_from(['read', 'write', 'admin'])),
)
def test_user_with_permissions(user: User, permissions: list[str]):
    """Test user with various permission sets."""
    result = apply_permissions(user, permissions)
    assert all(p in result.permissions for p in permissions)

Controlling shrinking

@composite
def ids_with_checksum(draw: DrawFn) -> str:
    """Generate IDs where parts must stay together during shrinking."""
    # Use map to preserve relationships during shrinking
    parts = draw(st.lists(st.integers(min_value=0, max_value=9), min_size=4, max_size=4))
    checksum = sum(parts) % 10
    return ''.join(map(str, parts)) + str(checksum)

Debugging strategies

# See what a strategy generates
from hypothesis import settings, Verbosity

@settings(verbosity=Verbosity.verbose)
@given(users())
def test_debug_user_generation(user: User):
    """See generated values."""
    pass  # Values printed to output

# Generate examples without running tests
from hypothesis import find

# Find example that satisfies predicate
example = find(users(), lambda u: u.active and len(u.name) > 5)

Checklist

  • Strategy generates valid domain data
  • Edge cases covered (empty, max size, special values)
  • Constraints properly enforced
  • Shrinking produces meaningful minimal examples
  • Strategy is composable with others

Additional resources:

More Other skills

Delegate independent tasks to specialized agents working concurrently with isolated context.

295.4K 206.3K
View

Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.

179.7K 100.1K
View

Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.

179.7K 89.5K
View

A set of resources to help me write all kinds of internal communications, using the formats that my company likes to use. Claude should use this skill whenever asked to write some sort of internal communications (status reports, leadership updates, 3P updates, company newsletters, FAQs, incident reports, project updates, etc.).

179.7K 76.1K
View

Fundamental design principles for writing maintainable, testable Python code.

40.2K 21.9K
View

Modern responsive layouts using container queries, fluid typography, CSS Grid, and mobile-first strategies.

40.2K 20K
View

Generate Playwright tests from scenarios using interactive browser exploration and validation.

39.7K 18.2K
View

Modern React state management with Redux Toolkit, Zustand, Jotai, and React Query for every state category.

40.2K 14.7K
View

GDPR-compliant data handling with consent management, data subject rights, and privacy controls.

40.2K 14.3K
View

Python error handling patterns including input validation, exception hierarchies, and partial failure handling. Use when implementing validation logic, designing exception strategies, handling batch processing failures, or building robust APIs.

40.2K 13.5K
View

Detailed multi-file refactor planning with safety checks and rollback guidance.

39.7K 13K
View