Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Built-in strategies

A strategy describes the values a test should be given. proptest has strategies for numbers, text, and collections, and combinators that build strategies out of other strategies.

Strategies are values: integers(0, 10) returns a strategy, which you can store in a variable and pass to several tests. Strategy constructors that check their arguments raise on invalid ones (for example integers(10, 0)), so call them from a raises function.

Exploring a strategy

example(strategy) returns one random value, which is handy for seeing what a strategy produces:

from proptest import example, lists, integers, text

def main() raises:
    for _ in range(3):
        print(example(lists(integers(0, 9), max_size=5)))
    print(example(text("abc", min_size=2, max_size=4)))

Use example for exploring, not in tests: a test should let given draw its values, so that failures can be shrunk and replayed.

find(strategy, condition) searches for a value satisfying a condition and returns the simplest one it finds:

from proptest import find, lists, integers

def main() raises:
    def sums_over_100(xs: List[Int]) -> Bool:
        var total = 0
        for x in xs:
            total += x
        return total > 100

    print(find(lists(integers(0, 50)), sums_over_100))   # [1, 50, 50]

Numbers

StrategyValues
integers(min_value, max_value)Int; either bound can be omitted
integers_of[DType.uint8](min_value, max_value)Scalar[dtype], for any integer DType
floats(min_value, max_value, allow_nan=, allow_infinity=, allow_subnormal=, exclude_min=, exclude_max=)Float64
floats32(...)Float32
booleans()Bool

Integers shrink towards zero, or towards the bound nearest zero. Floats shrink towards simple values: small integers first, then simple fractions. floats() generates NaN and the infinities unless bounds or the allow_ arguments exclude them.

Text

StrategyValues
text(alphabet, min_size=, max_size=)String; by default any codepoint except surrogates
characters(categories=, exclude_categories=, min_codepoint=, max_codepoint=, include_characters=, exclude_characters=, codec=)one-character String
from_regex(pattern, fullmatch=)String matching a regular expression
binary(min_size=, max_size=)List[UInt8]

alphabet can be a String of allowed characters or a characters(...) strategy:

from std.testing import assert_true, assert_equal
from proptest import *
def main() raises:
    var hex = (
text("0123456789abcdef", min_size=1)          # hex digits
    )
    var upper = (
text(characters(categories=["Lu", "Nd"]))     # uppercase letters and digits
    )
    var email = (
from_regex("[a-z]+@[a-z]+\\.com", fullmatch=True)
    )
    print(example(hex), example(upper), example(email))

Categories are Unicode general categories ("Lu", "Nd", or a whole class like "L"), from Unicode 17.0. Without fullmatch=True, from_regex generates strings that contain a match, as Hypothesis does.

Collections

StrategyValues
lists(elements, min_size=, max_size=)List[T]
unique_lists(elements, ...)List[T] with distinct elements
unique_lists_by(elements, key, ...)List[T] with distinct key(x)
sets(elements, ...)Set[T]
dictionaries(keys, values, ...)Dict[K, V]
tuples(s1, s2, ...)Tuple[...] of two to six elements
optionals(s)Optional[T], shrinking towards None

Collections shrink by deleting elements, then by shrinking the elements that remain.

Choosing among values

StrategyValues
just(x)always x
lazy_just(f)f(), called afresh for each test case
sampled_from([a, b, c], weights=)one of the elements
one_of(s1, ..., s6, weights=)a value from one of the strategies
permutations(xs)a reordering of xs
subsequence(xs, min_size=, max_size=)a sublist of xs, in order

sampled_from and one_of shrink towards their first option. The optional weights are positive integers that bias generation (weights=[1, 1, 8] picks the third option 80% of the time); they don’t change how values shrink.

Combinators

These build a strategy from other strategies; the next two pages cover them.

CombinatorValues
map(s, f)f(x) for x from s
apply(s1, ..., sN, f)f(a1, ..., aN)
filter(s, pred)x from s with pred(x)
filter_map(s, f)f(x) where it isn’t None
flatmap(s, f)a value from the strategy f(x)
composite(f)whatever f(data) draws and returns
recursive(base, extend)recursive data, such as trees
shared(s, key=)one value per test case, shared by every draw
boxed(s)the same values, as a BoxedStrategy[T]

Types

from_type[T]() chooses a strategy from a type: scalars, String, List, Optional, Set, Dict, tuples, and your own structs. See Strategies from types.

Everything else

The strategies reference lists every strategy and its arguments. NuMojo arrays have their own package; see Generate NuMojo arrays.