This question is similar to check unittest.mock call arguments agnostically w.r.t. whether they have been passed as positional arguments or keyword arguments, but with an extension.

Given a mocked function with a given spec, it is possible to check whether a function was called with the right arguments, regardless of whether the function was called with positional arguments or keyword arguments (or a mixture of both). So obviously, mock knows how to translate between those two.

My problem is a little more complicated, because given this signature:

def myfun(a, b, some_list, c=3, d=4)
    # Do something with a, b, c, d and some_list
    return None

all the following calls should be regarded as correct:

myfun(b=2, a=1, some_list = [3, 4, 5])
myfun(1, 2, [5, 4, 3])
myfun(1, 2, d=4, some_list=[4, 3, 5])

The values for a, b, c and d should be 1, 2, 3 and 4 respectively, but the value for some_list should just contain the values [3, 4, 5], without regard to order.

What I would like to do in a unittest is something like this (when complicated_fun should at one point call myfun with the given arguments):

def test_complicated_fun(self):
    myobject = MyClass(...)
    myobject.myfun = Mock(return_value = None, spec=myobject.myfun)
    myobject.complicated_fun()

    myobject.myfun.assert_called_once()
    self.assertEqual(myobject.myfun.call_args['a'], 1)
    self.assertEqual(myobject.myfun.call_args['b'], 2)
    self.assertEqual(myobject.myfun.call_args['c'], 3)
    self.assertEqual(myobject.myfun.call_args['d'], 4)
    self.assertCountEqual(myobject.myfun.call_args['mylist'], [3, 4, 5])

Except this will of course fail, seeing as we can't subscript call_args.

Is there a way around this, and to get the value of mylist directly from the mock? I could make a workaround it by using myobject.myfun.call_args[1].get('mylist', myobject.myfun.call_args[0][2]).

But that:

  • Depends on manually specifying again that mylist is the argument at index 2, meaning if my spec changes I should also manually edit the test.
  • Doesn't feel very pythonic
0

There are 0 best solutions below