You can make a custom strategy that draws recursively from a pool of built-in strategies and use the fixed_dictionaries strategy on the outside:
code of tests.py:
import json
import datetime
from string import ascii_letters, printable
from hypothesis import given, settings
from hypothesis.strategies import text, integers, booleans, emails, floats, dictionaries, recursive, lists, \
composite, datetimes, none, fixed_dictionaries
@composite
def string_timestamps(draw):
return str(draw(datetimes(min_value=datetime.datetime(year=2020, month=1, day=1),
max_value=datetime.datetime(year=2100, month=12, day=31))))
@composite
def random_lists(draw):
return draw(recursive(none() | booleans() | floats() | text(printable), lists))
@composite
def nested_dictionaries(draw):
"""
Builds random nested dictionary structure which is then used as JSON to
mask two fixed "token" keys.
"""
random_dict = draw(
dictionaries(text(),
none() | booleans() | integers() | floats() | text(printable) | random_lists() | emails() |
dictionaries(text(), none() | booleans() | integers() | floats() | text(printable)),
min_size=3,
max_size=10))
return random_dict
event = fixed_dictionaries({
'id': integers(min_value=1),
'kind': text(ascii_letters.upper(), min_size=1),
'payload': nested_dictionaries(),
'timestamp': string_timestamps(),
})
@given(event)
@settings(max_examples=10)
def test_foo(fixture):
print(json.dumps(fixture, indent=4, sort_keys=True))
Sample output with pytest -s tests.py:
{
"id": 17038,
"kind": "LE",
"payload": {
"": [
null,
null,
[
null,
false,
null,
null,
true,
"=um3]MuR2u`",
null,
false
]
],
"\u000f>": -3.664819488444682e+16,
"\u00122Y\uda6a\udf67": 1.192092896e-07,
"=\ud883\udf9bm\u00f5\ud862\udd3b": "#F\u000bUvs'g[C`",
"c\u00d9\u0018": {
"\ud937\ude82\u00d0": null
},
"\u0098\ud8c9\ude2b\udb4c\udc8e9p\udaa1\udd39": -21914,
"\u00b2\u00d2\u9521\uda9d\ude69\u00f8\udbf9\udca0\udb9f\udf9a\ud961\udfb5\ud8f7\udc77\ud9c1\ude5a9&\u001b": "Je]#Y",
"\u00d1\ud996\udc09\u009e\u00a7\u00fc": null,
"\u00f3\u0080\u00d6": {
"": "=Qmh+?P'4+~=\u000bU|",
"6\ud8a2\udd58\u0011\u001a": null,
">\u00b3": -25421,
"X(\udaa6\udceb=n?\u0011\u00f27t\u0012%\u00ee": false,
"^3b\u0090J\u0094\u00a5h\udb10\ude3b\u0092": -1.4760699148152035e-226,
"^\u0098W)\u00b0\u00a1\u0090cU\u00c0": null,
"r": true,
"s\u00c7\u0013": -78,
"\u0099": null,
"\u00f8\u009a\ud85f\udf31\b\u00a4\u00e7\u00a7\u00fdu": 17917,
"\udaf3\udcba\ud896\ude74\u0000\u00f7\u00ffi\u00d1\ud974\udf92": "tN"
},
"\ud85f\udc9e\u00a4\u00c5\ud84f\udfb3\u0097\u6da8": "p-c"
},
"timestamp": "2063-11-25 19:41:00.653220"
}