Search code examples
pythonunit-testingpython-hypothesis

How to make custom Hypothesis strategy to supply custom objects?


Suppose I have a class Thing

class Thing:

    def __init__(self, x, y):
        ...

And suppose I have a function which acts on a list of things.

def do_stuff(list_of_things):
    ...

I would like to write unit tests for do_stuff involving different instances of lists of Thing.

Is there a way to define a custom Hypothesis strategy which provides examples of list_of_things for my unit tests on do_stuff?


Solution

  • No need for a complicated composite strategy; this is a perfect case for the st.builds() strategy:

    from hypothesis import given, strategies as st
    
    @given(
        st.lists(
            st.builds(Thing, x=st.integers(), y=st.integers())
        )
    )
    def test_do_stuff(ls):
        do_stuff(ls)
    

    If Thing.__init__ has type annotations, you can omit strategies for the required arguments and st.builds() will fill them in for you (recursively, if it takes an instance of Foo!). You can also use type annotations in your test, and have Hypothesis infer the strategies entirely:

    @given(ls=...)  # literal "...", Python's ellipsis object
    def test_do_stuff(ls: list[Thing], tmpdir):  # and tmpdir fixture
        do_stuff(ls)
    
    @given(...)  # this will provide _all_ arguments, so no fixtures
    def test_do_stuff(ls: list[Thing]):
        do_stuff(ls)