I'm using hypothesis to test a function that takes two lists of equal length as input.
import hypothesis.strategies as st
from hypothesis import assume, given
@given(st.lists(ints, min_size=1),
st.lists(ints, min_size=1),
)
def test_my_func(x, y):
assume(len(x) == len(y))
# Assertions
This gives me the error message:
FailedHealthCheck: It looks like your strategy is filtering out a lot of data. Health check found 50 filtered examples but only 4 good ones.
The assumption that len(x) == len(y)
is filtering out too many inputs. So I would like to generate a random positive number and use that as the length of both x
and y
. Is there a way this can be done?
I found an answer using the @composite
decorator.
import hypothesis.strategies as st
from hypothesis import given
@st.composite
def same_len_lists(draw):
n = draw(st.integers(min_value=1, max_value=50))
fixed_length_list = st.lists(st.integers(), min_size=n, max_size=n)
return (draw(fixed_length_list), draw(fixed_length_list))
@given(same_len_lists())
def test_my_func(lists):
x, y = lists
# Assertions
The other solutions give nice reusable strategies. Here's a short low-tech solution, perhaps better suited to one-off use since you need to do one line of processing in the test function. We use zip to tranpose a list of pairs (2-element tuples); conceptually we're turning a n x 2
matrix into a 2 x n
matrix.
import hypothesis.strategies as st
from hypothesis import given
pair_lists = st.lists(st.tuples(st.integers(), st.integers()), min_size=1)
@given(pair_lists)
def test_my_func(L):
x, y = map(list, zip(*L))
Warning: It is crucial to have min_size=1
because zip
will give nothing if the list is empty.
You can use flatmap
to generate data that depends on other generated data.
import hypothesis.strategies as st
from hypothesis import assume, given
from hypothesis.strategies import integers as ints
same_len_lists = ints(min_value=1, max_value=100).flatmap(lambda n: st.lists(st.lists(ints(), min_size=n, max_size=n), min_size=2, max_size=2))
@given(same_len_lists)
def test_my_func(lists):
x, y = lists
assume(len(x) == len(y))
It's a little clumsy, and I'm not very happy about having to unpack the lists inside the test body.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With