Python

Verified against Claude Code · 2026-08-03

Write property-based tests with Hypothesis for a function with a large input space

A prompt for designing Hypothesis strategies and invariant properties for a function whose bugs live in inputs nobody thought to write an example test for, instead of a handful of manually chosen example-based test cases that only cover what the author already imagined.

Claude CodeChatGPT (GPT-5.1)Cursor 2.14 fillable variables

The prompt

Ready to copy — highlighted parts are example details you can swap.

Write property-based tests using Hypothesis for the function below, instead of (or alongside) example-based tests. The goal is to find inputs that break an invariant nobody thought to write a manual test case for — that's the entire reason to reach for Hypothesis over a hand-picked example.

FUNCTION UNDER TEST
def merge_intervals(intervals: list[tuple[int, int]]) -> list[tuple[int, int]]: merges overlapping (start, end) intervals.

KNOWN INVARIANTS
The merged output covers exactly the same total range as the input; no two intervals in the output overlap; the output is sorted by start.

INPUT DOMAIN CONSTRAINTS
Each interval has start <= end; the list can be empty; intervals can be given in any order, not just sorted.

SUSPECTED WEAK SPOT
Intervals that touch exactly at a boundary (one ends where the next begins) — unclear if the current code treats that as overlapping or not.

REQUIREMENTS
1. Design a Hypothesis strategy (st.integers(), st.text(), st.builds(...), or a composed strategy) that actually respects Each interval has start <= end; the list can be empty; intervals can be given in any order, not just sorted. — a strategy too loose generates inputs the function was never meant to handle and produces false-failure noise; a strategy too narrow misses the real edge cases Hypothesis exists to find. State why the chosen strategy matches the real domain.
2. State each property being tested as an invariant that should hold for every valid input, not as "the output equals this specific value" — a property test asserting a hardcoded expected output for one specific generated input isn't testing a property, it's a disguised (and fragile) example test. Cover at least: The merged output covers exactly the same total range as the input; no two intervals in the output overlap; the output is sorted by start., plus any property implied by the function's own contract (e.g. a sort function's output should always be the same length as its input and contain the same elements).
3. Specifically target Intervals that touch exactly at a boundary (one ends where the next begins) — unclear if the current code treats that as overlapping or not. with a strategy that's more likely to generate inputs near that boundary, using st.integers(min_value=..., max_value=...) or filters/mapping to bias generation toward the suspicious region rather than relying on uniform random luck to eventually hit it.
4. Use assume() to discard genuinely invalid generated inputs rather than writing a strategy so constrained it never explores the boundary of what's valid, and explain the difference between the two approaches for this specific case.
5. If Hypothesis finds a failing example, don't just report the raw random-looking input — explain what property it violates and why that specific shape of input is the minimal case Hypothesis's shrinking found, since that minimal case is usually the one that actually explains the bug.
6. Use @settings(max_examples=...) deliberately rather than accepting the library default everywhere — a property with a small, well-bounded input space needs far fewer generated examples to be exhausted than one with a large or unbounded space, and running the default example count uniformly wastes time on simple properties while sometimes under-exploring genuinely large ones.

OUTPUT FORMAT
1. The Hypothesis strategies used, with a one-line justification each.
2. The property test functions.
3. If you can identify a case that would actually fail with the current implementation, show it and explain the violated invariant — don't just assert the tests would pass without checking.
4. Any @settings override applied and why the default example count wasn't the right fit here.

Customize

Optional — swap in your own details for the highlighted parts above.

Why this works

Requiring properties to be stated as invariants rather than fixed expected outputs directly targets the most common way people misuse Hypothesis the first time they try it: writing @given(st.integers()) and then asserting my_func(x) == some_hardcoded_value, which either only works for a trivial function or quietly reduces to an example test with random inputs bolted on, defeating the entire point — Hypothesis's value is in checking a relationship that must hold across the whole input space (merged intervals cover the same total range as the input, regardless of what that range actually is), not a memorized single answer. The input_constraints field matters because Hypothesis's strategies generate literally anything in the type's range by default — st.integers() will happily generate negative numbers, zero, and values near sys.maxsize — so a strategy that doesn't encode the function's real preconditions either wastes most of its generated examples on inputs the function was never meant to handle (producing failures that are noise, not bugs) or, if filtered too aggressively with assume(), spends so much generation budget discarding invalid examples that it never gets deep into the actually interesting input space. The suspected_weak_spot field exploits something specific about how Hypothesis actually searches: its default generation is unbiased across the strategy's range, so a boundary condition — intervals meeting exactly edge-to-edge, an off-by-one at a comparison operator — can statistically take many runs to stumble into by pure chance, while a strategy deliberately biased toward that specific boundary (via min_value/max_value bounds or a composed strategy) finds it reliably in the very first run instead of leaving it to luck. Requiring the minimal shrunk failing example to be explained, not just reported, matters because Hypothesis's shrinking process is specifically designed to reduce a failing input to the smallest, simplest case that still reproduces the failure — that minimal case is usually the actual root cause laid bare, and reporting the original large random-looking failing input instead throws away the most useful part of what Hypothesis just did.

Verified against

Claude Code Sonnet 4.6 · 2026-08-03

Changelog

  • 2026-08-03 Initial publish, verified against Claude Code (Sonnet 4.6) on Hypothesis 6.115 and pytest 8.3.

Need this built into your business?

If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.

EXPLORE CUSTOM SOFTWARE
All Python prompts

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY