[SOLVED] Randomizing a user dataclass with pytest and hypothesis


This Content is from Stack Overflow. Question asked by OrenIshShalom

I can manually define an Address builder strategy:

import attrs
from hypothesis import given
import hypothesis.strategies as st

class Address:

    street: str
    city: str

AddressStrategy = st.builds(

def test_proper_address(address):
    assert len(address.city) < 4

When I run pytest, it indeed catches my bug:

address = Address(street='', city='0000') # <--- counterexample address found - good !

    def test_proper_address(address):
>       assert len(address.city) < 4
E       AssertionError: assert 4 < 4
E        +  where 4 = len('0000')
E        +    where '0000' = Address(street='', city='0000').city

main.py:23: AssertionError

According to the docs, it seems like it should be possible to use an auto-generated address builder:

builds() will be used automatically for classes with type annotations on init

But when I try the following options, neither work:

  • st.register_type_strategy(Address)
  • @given(Address)


# If you don't specify city and street, st.builds() will infer them from types
address_strategy = st.builds(Address)

# Or you can use various stronger grades of magic:

@given(st.from_type(Address))  # <-- get me an instance of this type
def test_proper_address(address): pass

@given(address=...)            # <-- infer the address strategy from type hints
def test_proper_address(address: Address): pass

@given(...)                    # <-- infer *all* strategies from type hints
def test_proper_address(name: str, address: Address): pass

The goal is that you can use as much magic as you like, but can also wind it back gradually if you need to customize just a little bit more of each strategy. For example, maybe we need at-most-length-four strings for the city?

address_strategy = st.builds(
    # street=st.text(),       # <-- no need to spell this out, it'll be inferred
    city=st.text(max_size=4)  # <-- but we do want to customize this one

# After we register this strategy, the more-magic options will infer it correctly:
st.register_type_strategy(Address, address_strategy)  # <-- e.g. in `conftest.py`

def test_proper_address(address: Address):
    assert len(address.city) < 4  # <-- this will pass now!

This Question was asked in StackOverflow by OrenIshShalom and Answered by Zac Hatfield-Dodds It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?