Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Hypothesis

ASecurity

Hypothesis is a Python library for property-based testing: a test states a rule that must hold for all inputs, and Hypothesis generates hundreds of inputs, including edge cases, then reports the simplest one that breaks the rule. Use when a user asks to write property-based tests, fuzz a Python function, find edge cases, test a round trip such as encode and decode, write stateful tests, reproduce a failing Hypothesis example, or tune Hypothesis settings and profiles for pytest and CI.

155 stars
0 votes
0 copies
0 views
Added 10/4/2026
developmentpythonrustgobashdjangotestingdebugginggitdatabase

Works with

terminalcli

Security Analysis

A96/100
mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned 10/4/2026

$npx -y skills add TerminalSkills/skills --skill hypothesis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hypothesis?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Hypothesis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-hypothesis/badge)](https://www.skillsdirectory.com/skills/terminalskills-hypothesis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: hypothesis
description: >-
  Hypothesis is a Python library for property-based testing: a test states a
  rule that must hold for all inputs, and Hypothesis generates hundreds of
  inputs, including edge cases, then reports the simplest one that breaks the
  rule. Use when a user asks to write property-based tests, fuzz a Python
  function, find edge cases, test a round trip such as encode and decode,
  write stateful tests, reproduce a failing Hypothesis example, or tune
  Hypothesis settings and profiles for pytest and CI.
license: Apache-2.0
compatibility: "Python 3.10+ (CPython or PyPy); runs under pytest or unittest"
metadata:
  author: terminal-skills
  version: "1.0.0"
  category: development
  tags: ["property-based-testing", "python", "testing", "pytest", "fuzzing"]
  repository: https://github.com/HypothesisWorks/hypothesis
---
# Hypothesis — Property-based testing for Python

## Overview

An ordinary test checks a few hand-picked inputs. A Hypothesis test describes the inputs with a strategy and asserts something that must be true for every one of them. Hypothesis runs the test 100 times by default with generated values, remembers failures, and shrinks a failing input to a minimal one. It fits pure functions, parsers, serializers, money and date arithmetic, and any code with an invariant that can be written down.

## Instructions

### Installation

```bash
pip install hypothesis pytest
pip install "hypothesis[cli]"      # adds the `hypothesis` command, including `hypothesis write`
```

Integrations come as extras with their own dependencies, among them `numpy`, `pandas`, `django`, `dateutil`, `pytz`, `lark`, `redis` and `codemods`: for example `pip install "hypothesis[numpy]"`.

### Write a property test

```python
from hypothesis import given, strategies as st

from billing.installments import split_installments


@given(
    total_cents=st.integers(min_value=0, max_value=5_000_000),
    count=st.integers(min_value=1, max_value=36),
)
def test_installments_add_up_to_the_total(total_cents, count):
    parts = split_installments(total_cents, count)
    assert len(parts) == count
    assert sum(parts) == total_cents
```

```bash
pytest tests/test_installments.py
```

The test is a normal function; pytest and unittest collect it as usual. `@given` fills arguments from the right, so a pytest fixture goes first in the signature, or all strategies are passed by keyword as above.

Properties that work well: a round trip returns the original (`decode(encode(x)) == x`), an invariant holds (sum, length, ordering), two implementations agree, an operation applied twice equals applying it once, valid input never raises.

### Choose strategies

| Strategy | Generates |
|---|---|
| `st.integers(min_value=0, max_value=120)` | integers in a range |
| `st.floats(min_value=0, max_value=1e6, allow_nan=False)` | floats; without bounds also `nan` and `inf` |
| `st.decimals(min_value="0.00", max_value="9999.99", places=2)` | `Decimal` values for money |
| `st.text(min_size=1, max_size=40)` | Unicode strings |
| `st.from_regex(r"[A-Z]{3}-[0-9]{4}", fullmatch=True)` | strings that match a pattern |
| `st.lists(st.integers(), min_size=1, unique=True)` | lists; also `st.sets`, `st.tuples`, `st.dictionaries` |
| `st.fixed_dictionaries({"sku": st.text(), "qty": st.integers(1, 20)})` | dictionaries with fixed keys |
| `st.sampled_from(["EUR", "USD", "GBP"])` | one of the given values, or an `Enum` member |
| `st.dates()`, `st.datetimes()`, `st.timedeltas()` | date and time values |
| `st.booleans()`, `st.none()`, `st.uuids()`, `st.emails()` | the named types |
| `st.one_of(st.none(), st.integers())` | a value from any of the strategies |
| `st.builds(Order, sku=st.text(), qty=st.integers(1, 20))` | instances of a class or results of a callable |
| `st.from_type(Order)` | a strategy derived from type annotations |

### Shape and combine inputs

```python
from hypothesis import assume, given, strategies as st

even_numbers = st.integers().map(lambda n: n * 2)
nonzero = st.integers().filter(lambda n: n != 0)


@st.composite
def date_ranges(draw):
    start = draw(st.dates())
    end = draw(st.dates(min_value=start))
    return (start, end)


@given(date_ranges())
def test_range_is_ordered(date_range):
    start, end = date_range
    assert start <= end


@given(st.integers(), st.integers())
def test_remainder_is_smaller_than_divisor(a, b):
    assume(b != 0)
    assert abs(a % b) < abs(b)
```

`.map` transforms values, `.filter` rejects values of one strategy, and `assume` rejects a whole test case. `@st.composite` builds inputs that depend on each other. When values must be drawn in the middle of a test, take `st.data()` as an argument and call `data.draw(strategy)`.

### Keep failures reproducible

```python
from hypothesis import example, given, strategies as st

from billing.installments import split_installments


@example(total_cents=1, count=2)
@given(total_cents=st.integers(0, 5_000_000), count=st.integers(1, 36))
def test_installments_add_up_to_the_total(total_cents, count):
    assert sum(split_installments(total_cents, count)) == total_cents
```

`@example` runs that exact input on every run, before the generated ones. Failures are also stored in the `.hypothesis/` directory and replayed first on the next run. To replay a CI failure locally, copy the `@reproduce_failure(...)` line from the CI output onto the test for the duration of the debugging session, or run `pytest --hypothesis-seed=20260914` with the seed you want.

### Settings and profiles

```python
import os

from hypothesis import Verbosity, settings

settings.register_profile("dev", max_examples=25)
settings.register_profile("ci", settings.get_profile("ci"), max_examples=500)
settings.register_profile("debug", max_examples=10, verbosity=Verbosity.verbose)
settings.load_profile(os.getenv("HYPOTHESIS_PROFILE", "dev"))
```

This belongs in `tests/conftest.py`. `HYPOTHESIS_PROFILE` is a variable this snippet reads; Hypothesis does not read it by itself. A single test is tuned with a decorator such as `@settings(max_examples=1000, deadline=None)`, placed above or below `@given`.

Two profiles are built in. `default` uses `max_examples=100` and a `deadline` of 200 milliseconds per test case. `ci` is selected automatically when the `CI` environment variable is set and adds `derandomize=True`, `deadline=None`, `database=None` and `print_blob=True`.

```bash
pytest --hypothesis-profile ci
pytest --hypothesis-show-statistics
pytest --hypothesis-verbosity=verbose
pytest --hypothesis-explain
```

### Stateful tests

```python
import hypothesis.strategies as st
from hypothesis import settings
from hypothesis.stateful import RuleBasedStateMachine, invariant, precondition, rule

from shop.cart import Cart


class CartMachine(RuleBasedStateMachine):
    def __init__(self):
        super().__init__()
        self.cart = Cart()
        self.model = {}

    @rule(sku=st.sampled_from(["MUG-11OZ", "TEE-M-BLK", "CAP-GRY"]), qty=st.integers(1, 20))
    def add(self, sku, qty):
        self.cart.add(sku, qty)
        self.model[sku] = self.model.get(sku, 0) + qty

    @precondition(lambda self: self.model)
    @rule(data=st.data())
    def remove(self, data):
        sku = data.draw(st.sampled_from(sorted(self.model)))
        self.cart.remove(sku)
        del self.model[sku]

    @invariant()
    def totals_match(self):
        assert self.cart.total_items() == sum(self.model.values())


TestCart = CartMachine.TestCase
TestCart.settings = settings(max_examples=50, stateful_step_count=30)
```

Hypothesis chooses sequences of rules, checks every invariant after each step, and prints a failing sequence as a short program. The pattern is to compare the real object with a simple model.

### Draft tests with the ghostwriter

```bash
hypothesis write billing.installments.split_installments
hypothesis write --roundtrip json.dumps json.loads
hypothesis write --equivalent billing.legacy.prorate billing.proration.prorate
```

The command prints test code to standard output. It takes dotted module or function names, not file paths. Treat the result as a first draft: narrow the strategies and add real assertions.

## Examples

### Example 1: A rounding bug in installment splitting

**Request:** "Write property tests for `split_installments(total_cents, count)` in `billing/installments.py`. The parts must always add up to the total."

The agent writes the test from "Write a property test" into `tests/test_installments.py` and runs it:

```bash
pytest tests/test_installments.py -q
```

**Result:**

```text
>       assert sum(parts) == total_cents
E       assert 0 == 1
E        +  where 0 = sum([0, 0])
E       Failing test case: test_installments_add_up_to_the_total(
E           total_cents=1,
E           count=2,
E       )
1 failed in 0.34s
```

One cent split in two loses the cent: the function returns `[total_cents // count] * count`. The agent distributes the remainder with `divmod`, pins the case with `@example(total_cents=1, count=2)`, and the run ends with `1 passed`.

### Example 2: A round trip between formatting and parsing

**Request:** "Check that `parse_money(format_money(cents))` always gives back the same amount."

```python
from hypothesis import given, strategies as st

from billing.money import format_money, parse_money


@given(st.integers(min_value=0, max_value=1_000_000_000))
def test_format_then_parse_returns_the_same_amount(cents):
    assert parse_money(format_money(cents)) == cents
```

**Result:**

```text
E       AssertionError: assert 56 == 57
E        +  where 56 = parse_money('0.57')
E        +    where '0.57' = format_money(57)
E       Failing test case: test_format_then_parse_returns_the_same_amount(
E           cents=57,
E       )
```

`parse_money` multiplies a float by 100 and truncates. The reported value differs between runs (57, 201, 431 and 7035 all fail), because not every amount is affected; every one of them points to the same defect. Parsing with `Decimal` fixes it.

## Guidelines

- **Assert a property, not a copy of the implementation.** A test that recomputes the result with the same formula passes even when the formula is wrong.
- **Never return early to skip an input.** `if b == 0: return` counts as a passing case and hides that nothing was checked. Use `assume` or a narrower strategy.
- **Prefer building valid inputs to filtering.** Heavy use of `.filter` or `assume` raises the `filter_too_much` health check and slows the run. Bounds, `.map` and `@st.composite` avoid it.
- **`\d` and `\w` in `st.from_regex` match all Unicode digits and letters.** Write `[0-9]` and `[A-Za-z]`, or pass `alphabet=st.characters(codec="ascii")`.
- **Floats include `nan` and infinity unless excluded.** `nan != nan` breaks equality assertions.
- **Function-scoped pytest fixtures run once per test, not once per generated input.** Hypothesis raises the `function_scoped_fixture` health check; create per-input state inside the test.
- **Tests must behave the same when replayed.** Global state, clocks, unseeded randomness and leftover files cause `FlakyFailure`.
- **The deadline is per test case.** Slow code fails with `DeadlineExceeded` at 200 ms; set `deadline=None` for tests that do real I/O rather than raising the limit blindly.
- **Do not leave `@reproduce_failure` in the code.** Its blob is tied to one Hypothesis version. Keep the input permanently with `@example`.
- **`.hypothesis/` is a local cache.** Hypothesis puts its own `.gitignore` inside, and entries can become invalid after an upgrade or a change to the test.
- **Keep generated inputs away from real systems.** Every test body runs at least 100 times: no production databases, payment calls, e-mail or file deletion driven by generated data. Use fakes or in-memory objects.
- **`hypothesis write` imports the target module**, which executes its top-level code. Run it only on code you trust.
- **Suppress health checks one at a time**, for example `@settings(suppress_health_check=[HealthCheck.too_slow])`, never with a blanket list.
- **When not to use it:** when no general rule can be stated (exact expected output for one specific input), for slow end-to-end tests, and for checking text or layout snapshots. Plain example-based tests are the better tool there.

Attribution

TerminalSkillsTerminalSkills
View sourceSee grades on GitHubMore from TerminalSkills →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

286712 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Writing Plans

Use when you have a spec or requirements for a multi-step task, before touching code

2927051 votes
View all in development →