than the largest element in the list” * of how to test, not what to test! A Simple Example* def test_sum_above_max_small(): xs = [1, 2, 3] assert sum(xs) > max(xs), ... def test_sum_above_max_large(): xs = [10, 20, 30] assert sum(xs) > max(xs), ... Escape from automanual testing with Hypothesis!
than the largest element in the list” A Simple Example import pytest @pytest.mark.parametrize('xs', [ [1, 2, 3], [10, 20, 30], ... ]) def test_sum_above_max(xs): assert sum(xs) > max(xs), ... Escape from automanual testing with Hypothesis!
than the largest element in the list” What do we learn? A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers())) def test_sum_above_max(xs): assert sum(xs) > max(xs), ... Escape from automanual testing with Hypothesis!
than the largest element in the list” What do we learn? • Error to call max([]) A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers())) def test_sum_above_max(xs): assert sum(xs) > max(xs), ... Falsifying example: test_sum_above_max(xs=[]) Traceback (most recent call last): ... ValueError: max() arg is an empty sequence Escape from automanual testing with Hypothesis!
than the largest element in the list” What do we learn? • Error to call max([]) A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers(), min_size=1)) def test_sum_above_max(xs): assert sum(xs) > max(xs), ... Escape from automanual testing with Hypothesis!
than the largest element in the list” What do we learn? • Error to call max([]) • Need greater or equal for 1-lists A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers(), min_size=1)) def test_sum_above_max(xs): assert sum(xs) > max(xs), ... Falsifying example: test_sum_above_max(xs=[0]) Traceback (most recent call last): ... AssertionError: xs=[0], sum(xs)=0, max(xs)=0 Escape from automanual testing with Hypothesis!
than the largest element in the list” What do we learn? • Error to call max([]) • Need greater or equal for 1-lists Escape from automanual testing with Hypothesis! A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers(), min_size=1)) def test_sum_above_max(xs): assert sum(xs) >= max(xs), ...
than the largest element in the list” What do we learn? • Error to call max([]) • Need greater or equal for 1-lists • Can’t have negative integers A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers(), min_size=1)) def test_sum_above_max(xs): assert sum(xs) >= max(xs), ... Falsifying example: test_sum_above_max(xs=[0, -1]) Traceback (most recent call last): ... AssertionError: xs=[0, -1], sum(xs)=-1, max(xs)=0 Escape from automanual testing with Hypothesis!
than the largest element in the list” What do we learn? • Error to call max([]) • Need greater or equal for 1-lists • Can’t have negative integers And this version works! A Simple Example from hypothesis import given from hypothesis.strategies import lists, integers @given(lists(integers(min_value=0), min_size=1)) def test_sum_above_max(xs): assert sum(xs) >= max(xs), ... Escape from automanual testing with Hypothesis!
times… • min_value and max_value args • type-specific args floats(allow_infinity=False) times(..., timezones=...) Collections are composed: • From elements and sizes • From keys or indices fancier options are later in the talk 13 See https://hypothesis.readthedocs.io/en/latest/data.html Values and Collections Escape from automanual testing with Hypothesis!
data • Run part of a test, then get more input • Useful with complex dataflow Custom strategies • Similar to interactive data in tests Advanced Options strat = deferred( lambda: integers() | lists(strat)) @given(data()) def test_something(data): i = data.draw(integers(...)) @composite def str_and_index(draw, min_size): s = draw(text(min_size=min_size)) i = draw(integers(min_size, len(s)) return (s, i) See https://hypothesis.readthedocs.io/en/latest/data.html Escape from automanual testing with Hypothesis!
from type hints • Objects from Attrs classes • Values for Numpy datatype • Data from a Django model • Many, many 3rd-party extensions Strong data validation makes testing easier! Inferring Data from Code Escape from automanual testing with Hypothesis!
to test • Cache location • Deterministic mode • and much more! Configure in code or from pytest Define and load custom profiles Configuring Hypothesis from hypothesis import given, settings, database from hypothesis.strategies import none settings.database = database.ExampleDatabase( "/path/to/cache/dir/" # or ":memory:" ) @settings(derandomize=True, max_examples=1000)) @given(...) def test_with_settings(x): ... See https://hypothesis.readthedocs.io/en/latest/settings.html Escape from automanual testing with Hypothesis!
example - % time generating data (~0 to ~20%) - define custom events Hypothesis runs a lot of tests! If your test is slow, running it hundreds of times will be really slow. (but you need fewer tests) Hypothesis runs your code under coverage - ~2x to ~5x slowdown - still improves bugs per unit time - can be disabled in pathological cases 19 Performance tips Escape from automanual testing with Hypothesis!
• Interpret as value according to strategy • Shrink bytestream, not value • More efficient than shrinking values • Track lots of metadata on targets • Use heuristics for better coverage 20 Secrets of Shrinking Escape from automanual testing with Hypothesis!
• Interpret as value according to strategy • Shrink bytestream, not value 21 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 1, 0, 1, 1, 0, ... out = [False, True, False, True]
elements • Then reduce bytes • Real shrinker is smarter Let’s shrink out, with any(out) == True 22 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 1, 0, 1, 1] out = [False, True, False, True]
elements • Then reduce bytes • Real shrinker is smarter Let’s shrink out, with any(out) == True 23 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 1, 0, 1, 0] out = [False, True, False, False]
elements • Then reduce bytes • Real shrinker is smarter Let’s shrink out, with any(out) == True 24 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 1, 0, 0, 0] out = [False, True, False]
elements • Then reduce bytes • Real shrinker is smarter Let’s shrink out, with any(out) == True 25 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 1, 0] out = [False, True, False]
elements • Then reduce bytes • Real shrinker is smarter Let’s shrink out, with any(out) == True 26 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 1, 1] out = [False, True, True]
elements • Then reduce bytes • Real shrinker is smarter Let’s shrink out, with any(out) == True 27 Secrets of Shrinking Escape from automanual testing with Hypothesis! lists(booleans(), min_size=3) stream = [0, 0, 1] out = [False, False, True]
subtract • json.dumps / json.loads or just related: • set_x / get_x • list.append / list.index Escape from automanual testing with Hypothesis! See https://fsharpforfunandprofit.com/posts/property-based-testing-2/
then… • multiply factors to get input Tokenise a string, then… • check each token is valid • concatenate to get input Escape from automanual testing with Hypothesis! See https://fsharpforfunandprofit.com/posts/property-based-testing-2/
list does not change the element counts (half of the definition of sorting!) Escape from automanual testing with Hypothesis! See https://fsharpforfunandprofit.com/posts/property-based-testing-2/
Good for filtering, databases, etc. Escape from automanual testing with Hypothesis! See https://fsharpforfunandprofit.com/posts/property-based-testing-2/