Reputation: 1308
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?
Upvotes: 15
Views: 2637
Reputation: 15288
What's about using dictionaries for this purpose?
You can specify generated data
For example if need only positive integers, use min_value=1
. If don't need empty list - min_size=1
for dictionary, etc.
from hypothesis import given
from hypothesis.strategies import integers, dictionaries
@given(
dicts=dictionaries(integers(min_value=1), integers(min_value=1), min_size=1)
)
def test_your_test(dicts):
x = list(dicts.values()) # or just dicts.values()
y = list(dicts.keys()) # or just dicts.keys()
assert len(x) == len(y)
Same way you can generate any lists with same length (list of strings or whatever)
Upvotes: 0
Reputation: 1402
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.
Upvotes: 1
Reputation: 1308
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
Upvotes: 17
Reputation: 60994
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.
Upvotes: 7