mcpField
H
hypothesis-testing

hypothesis-testing

github.com/laurigatesテスト・品質5975 回インストール今日更新
リポジトリ

hypothesis-testing について

Hypothesisを使うPython開発者向けのテストガイドです。入力データの生成、戦略や設定、CIでの実行、失敗時のデバッグを扱います。

主な機能

  1. 01プロパティベーステストの生成
  2. 02組み込み・カスタム戦略
  3. 03型注釈からの戦略生成
  4. 04プロファイルとテスト設定
  5. 05CI連携と失敗時のデバッグ

活用シーン

  1. 01数学的な不変条件の確認
  2. 02シリアライズ往復のテスト
  3. 03APIの境界ケースの探索
  4. 04NumPyや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/

エージェント向けの最適化

コンテキストコマンド
クイックチェック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 を参照してください。

コメント