I'm trying to generate complex tree like dictionaries for testing my code. the dictionaries are basically compound classes, that contains list of structs and more simpler fields.
I'm using hypothesis strategies deferred method, with a lambda function implementation, I want to map a certain generated 'key' to a specific strategy made for that 'key'. for some reason it's looks like my mapping doesn't work as expected and different 'keys' are getting different strategies.
would appreciate your assistance. thanks.
This is what I've tried:
name_strategy = st.text(min_size=0, max_size=10)
fanout_ref_strategy = st.lists(st.booleans())
MyClass_keys = [
"name",
"fanout_ref",
]
MyClass_strategy_mapping = {
"name": name_strategy,
"fanout_ref": fanout_ref_strategy,
}
MyClass_value_strategy = st.deferred(lambda: MyClass_key_strategy.map(MyClass_strategy_mapping.get) | MyClass_key_strategy)
MyClass_key_strategy = st.sampled_from(MyClass_keys)
MyClass_strategy = st.dictionaries(keys=MyClass_key_strategy, values=MyClass_value_strategy)
@given(specific_dict=MyClass_strategy)
def test_specific_dictionary(specific_dict):
# Your test code here
print(specific_dict)
This is the generated output I see:
{}
{}
{'name': text(max_size=10)}
{'fanout_ref': 'name', 'name': text(max_size=10)}
{'fanout_ref': text(max_size=10), 'name': text(max_size=10)}
{'fanout_ref': lists(booleans())}
{'fanout_ref': lists(booleans()), 'name': lists(booleans())}
{'fanout_ref': text(max_size=10), 'name': lists(booleans())}
{'name': lists(booleans()), 'fanout_ref': lists(booleans())}
{'name': lists(booleans()), 'fanout_ref': 'fanout_ref'}
{'name': text(max_size=10)}
{'name': text(max_size=10)}
I Was expecting to have dictionaries, with 'name' and 'fanout_ref' as keys, and strings and lists of boolean as values.
The idiomatic way to do this uses
st.fixed_dictionaries()
:Separately, you might want to understand why your example code doesn't work.
One bug is that the
keys=
andvalues=
strategies forst.dictionaries()
are completely independent - if you need specific values per key, you'll need to usefixed_dictionaries()
, or generate and merge a dictionary for each group of keys that share a values strategy.Another bug is that in
st.deferred(lambda: MyClass_key_strategy.map(MyClass_strategy_mapping.get) | MyClass_key_strategy)
st.deferred()
isn't doing anything| MyClass_key_strategy
says that you can generate values from the keys strategy.map()
returns the strategy as a value; to also draw from the returned strategy you need.flatmap()
. Here's the docs; it'd look like= MyClass_key_strategy.flatmap(MyClass_strategy_mapping.get)
.Finally,
st.dictionaries()
doesn't always generate all possible keys - you'd need to setmin_size=2
for this, although it's a really bad way to generate from a fixed set of keys relative tofixed_dictionaries
.