0

I have

class A(st.SearchStrategy):
  def do_draw(self, data):
     return object_a(b=st.integers(), c=st.boolean()...)

class B(st.SearchStrategy):
  def do_draw(self, data):
     return object_a(d=st.boolean(), e=st.boolean()...)

@given(a=A(), b=B())
def test_A_and_B(a, b):
  ...

How I make sure that a test case of

a = A(b=5, c=True)
# b can be anything

and a test case of

a = A(b=10, c=True)
b = B(c=True, d=<can be either T or F>)

get generate?

I know about @example. Would this be correct?

@given(a=A(), b=B())
@example(a=A(b=10, c=True), b=B(c=True, d=False)
# not sure how to set d to be either true or false
def test_A_and_B(a, b):
  ...

1 Answers1

3

DO NOT INHERIT FROM SEARCHSTRATEGY.
It is private, internal code that we might change at any time. You're using it wrong anyway!

Instead, you should compose your strategy from the documented functions in hypothesis.strategies. For example, you can define a strategy for making instances of object_a using builds() like so:

builds(object_a, b=st.integers(), c=st.booleans(), ...)

An @example is a single exact input, so you'd use it twice to check d both True and False:

@example(a=object_a(b=10, c=True), b=object_b(c=True, d=True)
@example(a=object_a(b=10, c=True), b=object_b(c=True, d=False)

If you don't care about the value of b at all, just define an example with the default value for that argument.

All together, that would look like:

@given(
    a=builds(object_a, b=st.integers(), c=st.booleans()), 
    b=builds(object_b, d=st.booleans(), e=st.booleans()
)
@example(a=object_a(b=5, c=True), b=None)  # assuming b=None is valid
@example(a=object_a(b=10, c=True), b=object_b(d=True, e=True))
@example(a=object_a(b=10, c=True), b=object_b(d=True, e=False))
def test_A_and_B(a, b):
    ...

Hope that helps :-)

Zac Hatfield-Dodds
  • 2,455
  • 6
  • 19