Strategy Generation¶
The generation module creates Hypothesis strategies for generating test data. It provides type-to-strategy mapping, path parameter generation, request body generation, and header generation.
Overview¶
pytest-routes uses Hypothesis for property-based testing. The generation module bridges your application’s type system with Hypothesis strategies:
Type Strategies - Map Python types to Hypothesis strategies
Path Parameters - Generate valid path parameter values
Request Bodies - Generate request payloads from models
Headers - Generate HTTP headers for authentication, content-type, etc.
Quick Start¶
Get a strategy for any type:
from pytest_routes import strategy_for_type
from hypothesis import given
# Built-in types work automatically
int_strategy = strategy_for_type(int)
str_strategy = strategy_for_type(str)
# Use in Hypothesis tests
@given(value=strategy_for_type(int))
def test_with_integers(value: int):
assert isinstance(value, int)
Register custom types:
from hypothesis import strategies as st
from pytest_routes import register_strategy
class UserId:
def __init__(self, value: int):
self.value = value
register_strategy(
UserId,
st.builds(UserId, value=st.integers(min_value=1, max_value=1000000))
)
Built-in Type Strategies¶
The following types have pre-registered strategies:
Type |
Strategy |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Generic types are also supported:
from pytest_routes import strategy_for_type
# Optional[str] -> st.none() | st.text()
strategy_for_type(Optional[str])
# list[int] -> st.lists(st.integers())
strategy_for_type(list[int])
# dict[str, int] -> st.dictionaries(st.text(), st.integers())
strategy_for_type(dict[str, int])
API Reference¶
Type Strategies¶
Strategy Registration Functions¶
- pytest_routes.generation.strategies.register_strategy(typ, strategy, *, override=False)[source]¶
Register a custom strategy for a type.
- Parameters:
typ (
type) – The Python type.strategy (
SearchStrategy[Any]) – The Hypothesis strategy to use for this type.override (
bool) – If True, allow overriding an existing strategy. If False (default), raise ValueError if a strategy is already registered for this type.
- Raises:
ValueError – If a strategy is already registered and override is False.
- Return type:
Examples
>>> from hypothesis import strategies as st >>> register_strategy(MyType, st.builds(MyType)) >>> register_strategy(MyType, st.builds(MyType, arg="new"), override=True)
Register a permanent strategy for a type.
Example
from hypothesis import strategies as st from pytest_routes import register_strategy # Register for a custom type register_strategy( MyType, st.builds(MyType, name=st.text(min_size=1)) ) # Override an existing strategy register_strategy( str, st.text(min_size=5, max_size=20), override=True )
- pytest_routes.generation.strategies.unregister_strategy(typ)[source]¶
Unregister a custom strategy.
- Parameters:
typ (
type) – The Python type to unregister.- Return type:
- Returns:
True if the type was previously registered, False otherwise.
Examples
>>> from hypothesis import strategies as st >>> register_strategy(MyType, st.builds(MyType)) >>> unregister_strategy(MyType) True >>> unregister_strategy(MyType) False
- pytest_routes.generation.strategies.register_strategies(mapping, *, override=False)[source]¶
Register multiple strategies at once.
- Parameters:
mapping (
dict[type,SearchStrategy[Any]]) – Dictionary mapping types to their strategies.override (
bool) – If True, allow overriding existing strategies. If False (default), raise ValueError if any type already has a registered strategy.
- Raises:
ValueError – If any type is already registered and override is False.
- Return type:
Examples
>>> from hypothesis import strategies as st >>> register_strategies( ... { ... MyType1: st.builds(MyType1), ... MyType2: st.builds(MyType2), ... } ... )
Register multiple strategies at once.
Example
from hypothesis import strategies as st from pytest_routes import register_strategies register_strategies({ UserId: st.builds(UserId, st.integers(min_value=1)), Email: st.emails(), PhoneNumber: st.from_regex(r"\+\d{10,15}"), })
Strategy Helpers¶
- pytest_routes.generation.strategies.strategy_for_type(typ)[source]¶
Get a Hypothesis strategy for a Python type.
- Parameters:
typ (
type) – The Python type to generate values for.- Return type:
- Returns:
A Hypothesis SearchStrategy for the type.
The main function for getting a strategy for any type.
Type Resolution
The function resolves types in this order:
Direct lookup in the registry
Optional[X]unwrappinglist[X]anddict[K, V]handlingDataclass/Pydantic model detection
Hypothesis
from_type()fallbackText fallback for unknown types
- pytest_routes.generation.strategies.strategy_provider(typ)[source]¶
Decorator to register a strategy provider function.
- Parameters:
typ (
type) – The Python type to register a strategy for.- Return type:
Callable[[Callable[[],SearchStrategy[Any]]],Callable[[],SearchStrategy[Any]]]- Returns:
Decorator function that registers the strategy when applied.
Examples
>>> from hypothesis import strategies as st >>> @strategy_provider(MyType) ... def my_custom_strategy(): ... return st.builds(MyType, field=st.text())
Decorator for registering strategy provider functions.
Example
from pytest_routes import strategy_provider from hypothesis import strategies as st @strategy_provider(MyComplexType) def my_complex_strategy(): return st.builds( MyComplexType, field1=st.text(), field2=st.integers(), )
- pytest_routes.generation.strategies.temporary_strategy(typ, strategy)[source]¶
Temporarily register a strategy for the duration of a context.
The original strategy (if any) is restored when the context exits.
- Parameters:
typ (
type) – The Python type.strategy (
SearchStrategy[Any]) – The temporary Hypothesis strategy to use.
- Yields:
None
- Return type:
Examples
>>> from hypothesis import strategies as st >>> with temporary_strategy(str, st.just("test")): ... # str strategy is now st.just("test") ... result = strategy_for_type(str).example() >>> # Original str strategy is restored
Context manager for temporary strategy registration.
Example
from pytest_routes import temporary_strategy, strategy_for_type from hypothesis import strategies as st # Normal str strategy normal = strategy_for_type(str).example() with temporary_strategy(str, st.just("fixed")): # Inside context, str always generates "fixed" assert strategy_for_type(str).example() == "fixed" # Original strategy restored
Path Parameters¶
Path parameter generation.
- pytest_routes.generation.path.generate_path_params(path_params, path)[source]¶
Generate valid path parameter combinations.
- pytest_routes.generation.path.format_path(path, params)[source]¶
Format a path pattern with parameter values.
Path parameter generation handles URL path variables:
from pytest_routes.generation.path import generate_path_params, format_path
# Generate values for path parameters
path_params = {"user_id": int, "post_id": int}
strategy = generate_path_params(path_params, "/users/{user_id}/posts/{post_id}")
# Format a path with generated values
values = {"user_id": 42, "post_id": 123}
url = format_path("/users/{user_id}/posts/{post_id}", values)
# Result: "/users/42/posts/123"
Request Bodies¶
Request body generation.
- pytest_routes.generation.body.generate_body(body_type)[source]¶
Generate request body based on type annotation.
Request body generation creates payloads for POST/PUT/PATCH requests:
from pytest_routes.generation.body import generate_body
from pydantic import BaseModel
class CreateUserRequest(BaseModel):
name: str
email: str
age: int
# Generate valid request bodies
body_strategy = generate_body(CreateUserRequest)
example = body_strategy.example()
# Result: {"name": "...", "email": "...", "age": ...}
Header Generation¶
Header generation strategies for HTTP requests.
- pytest_routes.generation.headers.register_header_strategy(header_name, strategy)[source]¶
Register a custom strategy for a specific HTTP header.
This allows users to override default header generation or add strategies for custom headers.
- Parameters:
header_name (
str) – The HTTP header name (case-insensitive).strategy (
SearchStrategy[str]) – A Hypothesis strategy that generates string values.
- Return type:
Example
>>> from hypothesis import strategies as st >>> register_header_strategy("X-Custom-ID", st.uuids().map(str))
- pytest_routes.generation.headers.generate_headers(header_specs=None, *, include_content_type=False, include_accept=False, include_authorization=False)[source]¶
Generate HTTP headers based on specifications.
All header values are generated as strings to comply with HTTP standards.
- Parameters:
header_specs (
dict[str,type] |None) – Mapping of header names to their types. If None, only optional headers based on flags will be included.include_content_type (
bool) – Whether to include Content-Type header.include_accept (
bool) – Whether to include Accept header.include_authorization (
bool) – Whether to include Authorization header.
- Return type:
SearchStrategy[dict[str,str]]- Returns:
A Hypothesis strategy that generates dictionaries of HTTP headers.
Example
>>> from hypothesis import strategies as st >>> # Generate custom headers >>> header_strategy = generate_headers( ... header_specs={"X-Request-ID": str, "X-Trace-ID": str}, ... include_accept=True, ... ) >>> # Generate only standard headers >>> standard_headers = generate_headers( ... include_content_type=True, ... include_accept=True, ... )
- pytest_routes.generation.headers.generate_optional_headers(required_headers=None, optional_headers=None)[source]¶
Generate headers with required and optional fields.
This is useful for testing routes where some headers are mandatory and others are optional.
- Parameters:
- Return type:
SearchStrategy[dict[str,str]]- Returns:
A Hypothesis strategy that generates dictionaries of HTTP headers.
Example
>>> header_strategy = generate_optional_headers( ... required_headers={"Authorization": str}, ... optional_headers={"X-Request-ID": str, "X-Trace-ID": str}, ... )
Header generation provides strategies for HTTP headers:
from pytest_routes import (
generate_headers,
generate_optional_headers,
register_header_strategy,
)
# Generate required headers
headers = generate_headers(["Authorization", "Content-Type"])
# Generate optional headers (may or may not be present)
optional = generate_optional_headers(["X-Request-ID", "X-Trace-ID"])
# Register a custom header strategy
from hypothesis import strategies as st
register_header_strategy(
"Authorization",
st.just("Bearer test-token-12345")
)
Advanced Usage¶
Pydantic Model Strategies¶
pytest-routes automatically generates strategies for Pydantic models:
from pydantic import BaseModel, Field
from pytest_routes import strategy_for_type
class User(BaseModel):
id: int = Field(ge=1)
name: str = Field(min_length=1, max_length=100)
email: str
# Automatically creates a valid User strategy
user_strategy = strategy_for_type(User)
user = user_strategy.example()
Dataclass Strategies¶
Dataclasses are also supported:
from dataclasses import dataclass
from pytest_routes import strategy_for_type
@dataclass
class Point:
x: float
y: float
point_strategy = strategy_for_type(Point)
point = point_strategy.example()
Constrained Strategies¶
For more control, register constrained strategies:
from hypothesis import strategies as st
from pytest_routes import register_strategy
# Positive integers only
register_strategy(
int,
st.integers(min_value=0, max_value=10000),
override=True
)
# Email-like strings
class Email(str):
pass
register_strategy(
Email,
st.emails()
)
See Also¶
Route Discovery - How routes and types are extracted
Test Execution - How generated data is used in tests
Hypothesis documentation - Full Hypothesis docs