关于 hypothesis-testing
面向 Python 开发者的 Hypothesis 测试指南,可生成测试输入并验证代码属性。内容涵盖策略、配置、CI 集成与故障调试。
主要功能
- 01生成基于属性的测试
- 02内置与自定义策略
- 03按类型注解生成策略
- 04配置测试配置档与选项
- 05CI 集成与失败调试
适用场景
- 01检查数学不变量
- 02测试序列化往返
- 03探索 API 边界情况
- 04生成 NumPy 或 Django 测试数据
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ laurigates/ claude-plugins --skill hypothesis-testing安装后在 Claude Code 中输入/hypothesis-testing确认已加载。
附带文件REFERENCE.md
详细介绍
Hypothesis 属性测试
自动生成测试用例,以发现边界情况并验证代码的属性。
何时使用此技能
| 在以下情况下使用此技能…… | 在以下情况下改用 property-based-testing…… |
|---|---|
| 使用 Hypothesis 编写 Python 属性测试 | 使用非 Python 语言(TS、Rust 等) |
| 为序列化往返生成测试数据 | 编写基于示例的测试(使用 python-testing) |
| 验证数学不变量(交换律、结合律) | 运行现有测试套件(使用 test-run) |
| 使用 NumPy 或 Django 策略扩展 | 设计整体测试策略(使用 test-consult) |
何时使用 Hypothesis,何时使用基于示例的测试
| 在以下情况下使用 Hypothesis…… | 在以下情况下使用基于示例的测试…… |
|---|---|
| 测试数学属性(交换律、结合律) | 测试已知的特定边界情况 |
| 需要测试许多有效输入 | 已知具体取值的业务逻辑 |
| 验证序列化往返 | 测试特定错误消息 |
| 发现无法预测的边界情况 | 与外部系统集成 |
| 测试参数众多的 API | 测试 UI 行为 |
安装
uv add --dev hypothesis pytest
# Optional extensions
uv add --dev hypothesis[numpy] # NumPy strategies
uv add --dev hypothesis[django] # Django model strategies
配置
# pyproject.toml
[tool.hypothesis]
max_examples = 200
deadline = 1000
[tool.hypothesis.profiles.dev]
max_examples = 50
deadline = 1000
[tool.hypothesis.profiles.ci]
max_examples = 500
deadline = 5000
verbosity = "verbose"
# Activate profile
from hypothesis import settings, Phase
settings.load_profile("ci") # Use in conftest.py
基本用法
from hypothesis import given, example, assume
import hypothesis.strategies as st
# Test a property
@given(st.integers(), st.integers())
def test_addition_commutative(a, b):
assert a + b == b + a
# Add explicit edge cases
@given(st.integers())
@example(0)
@example(-1)
@example(2**31 - 1)
def test_with_explicit_examples(x):
assert process(x) is not None
# Skip invalid inputs
@given(st.floats(allow_nan=False, allow_infinity=False),
st.floats(allow_nan=False, allow_infinity=False))
def test_safe_divide(a, b):
assume(b != 0)
result = a / b
assert isinstance(result, float)
核心策略
import hypothesis.strategies as st
# Primitives
st.integers() # Any integer
st.integers(min_value=0, max_value=100) # Bounded
st.floats(allow_nan=False) # Floats without NaN
st.booleans() # True/False
st.text() # Unicode strings
st.text(min_size=1, max_size=50) # Bounded strings
st.binary() # Bytes
# Collections
st.lists(st.integers()) # List of ints
st.lists(st.text(), min_size=1) # Non-empty list
st.dictionaries(st.text(), st.integers()) # Dict
st.tuples(st.integers(), st.text()) # Fixed tuple
# Special types
st.emails() # Valid emails
st.uuids() # UUID objects
st.datetimes() # datetime objects
# Choices
st.sampled_from(["a", "b", "c"]) # Pick from list
st.one_of(st.integers(), st.text()) # Union type
st.none() | st.integers() # Optional int
自定义组合策略
from hypothesis.strategies import composite
@composite
def users(draw):
return {
"id": draw(st.integers(min_value=1)),
"name": draw(st.text(min_size=1, max_size=50)),
"email": draw(st.emails()),
"active": draw(st.booleans())
}
@given(users())
def test_user_validation(user):
assert user["id"] > 0
assert "@" in user["email"]
根据类型注解生成
from hypothesis import given
from hypothesis.strategies import from_type
from dataclasses import dataclass
@dataclass
class Config:
name: str
port: int
debug: bool
@given(from_type(Config))
def test_config(config: Config):
assert isinstance(config.name, str)
assert isinstance(config.port, int)
常见属性模式
# 1. Round-trip (encode/decode)
@given(st.text())
def test_json_roundtrip(data):
assert json.loads(json.dumps(data)) == data
# 2. Idempotency (applying twice = applying once)
@given(st.lists(st.integers()))
def test_sort_idempotent(items):
assert sorted(sorted(items)) == sorted(items)
# 3. Invariant preservation
@given(st.lists(st.integers()))
def test_sort_preserves_length(items):
assert len(sorted(items)) == len(items)
# 4. Oracle (compare implementations)
@given(st.integers(min_value=0, max_value=20))
def test_fibonacci(n):
assert fast_fib(n) == slow_fib(n)
CI 集成
# .github/workflows/test.yml
- name: Run hypothesis tests
run: |
uv run pytest \
--hypothesis-show-statistics \
--hypothesis-profile=ci \
--hypothesis-seed=${{ github.run_number }}
- name: Upload hypothesis database
uses: actions/upload-artifact@v4
if: failure()
with:
name: hypothesis-examples
path: .hypothesis/
Agentic 优化
| 场景 | 命令 |
|---|---|
| 快速检查 | pytest -x --hypothesis-seed=0 -q |
| 快速失败 | pytest --hypothesis-profile=dev -x --tb=short |
| CI 模式 | pytest --hypothesis-profile=ci --hypothesis-show-statistics |
| 可复现 | pytest --hypothesis-seed=42 |
| 调试失败用例 | pytest -x -s --hypothesis-verbosity=debug |
| 不进行缩减 | 在 @settings 中添加 phases=[Phase.generate] |
快速参考
# Core decorators
@given(strategy) # Generate test inputs
@example(value) # Add explicit test case
@settings(max_examples=500) # Configure behavior
# Key settings
assume(condition) # Skip invalid inputs
note(message) # Add debug info to failure
target(value) # Guide generation toward value
有关高级模式(有状态测试、递归数据、设置)、最佳实践和调试指南,请参阅 REFERENCE.md。
评论
支持 Markdown