Search code examples
pythonpython-3.xpytestpython-unittest

Is there a way to use "assert_called_with" that only checks specific word?


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?


Solution

  • 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:

    • if you are not sure that the function has always an argument, you have to add a check (e.g. for args[0])
    • if the argument can also be called as a keyword argument, you have to expand the check (args[1] would give you the dictionary of keyword arguments)
    • the function dict_contains_key_value can be optimized and extended if needed, this is just a simple example