I am trying to use assert_called_with
to assert the argument that is passed to the mocked object. There is only one argument of that function but the argument is very large.
{"A":{"B": {"C" : {"D": {"key": "keyword", "any": "aaa", "anything": "bbbb"}}}}
I only care about "key": "keyword"
exists and do not care about other stuff, is there a way to do so?
Assuming that your function has one argument, that is a nested dictionary and shall on some level contain the specific key/value pair, you have to iterate over that dictionary manually using some function.
You get the arguments of all calls of your mocked function from call_args_list
. Each entry contains a tuple with the list of positional arguments and the keyword arguments, e.g. call_args_list[0][0][0]
contains the first positional argument of the first call.
Assuming that your tested function have always exactly one arguments, that is called as a positional argument, you can do something like this:
def dict_contains_key_value(arg, key, value):
if not isinstance(arg, dict):
return False
for k, v in arg.items():
if k == key and v == value:
return True
if dict_contains_key_value(v, key, value):
return True
return False
@mock.patch("my_module.sut")
def test_called_arg(mocked):
caller() # the function that calls `sut()` several times
mocked.assert_called()
assert any(dict_contains_key_value(args[0][0], "key", "keyword")
for args in mocked.call_args_list)
A few notes:
args[0]
)args[1]
would give you the dictionary of keyword arguments)dict_contains_key_value
can be optimized and extended if needed, this is just a simple example