Python mock call_args_list unpacking tuples for assertion on arguments Python mock call_args_list unpacking tuples for assertion on arguments python python

Python mock call_args_list unpacking tuples for assertion on arguments


I think that many of the difficulties here are wrapped up in the treatment of the "call" object. It can be thought of as a tuple with 2 members (args, kwargs) and so it's frequently nice to unpack it:

args, kwargs = call

Once it's unpacked, then you can make your assertions separately for args and kwargs (since one is a tuple and the other a dict)

def test_foo(self):    def foo(fn):        fn('PASS and some other stuff')    f = Mock()    foo(f)    foo(f)    foo(f)    for call in f.call_args_list:        args, kwargs = call        self.assertTrue(all(a.startswith('PASS') for a in args))

Note that sometimes the terseness isn't helpful (e.g. if there is an error):

for call in f.call_args_list:    args, kwargs = call    for a in args:        self.assertTrue(a.startswith('PASS'), msg="%s doesn't start with PASS" % a)


A nicer way might be to build up the expected calls your self then use a direct assertion:

>>> from mock import call, Mock>>> f = Mock()>>> f('first call')<Mock name='mock()' id='31270416'>>>> f('second call')<Mock name='mock()' id='31270416'>>>> expected_calls = [call(s + ' call') for s in ('first', 'second')]>>> f.assert_has_calls(expected_calls)

Note that the calls must be sequential, if you don't want that then override the any_order kwarg to the assertion.

Also note that it's permitted for there to be extra calls before or after thespecified calls. If you don't want that, you'll need to add another assertion:

>>> assert f.call_count == len(expected_calls)

Addressing the comment of mgilson, here's an example of creating a dummy object that you can use for wildcard equality comparisons:

>>> class AnySuffix(object):...     def __eq__(self, other):...         try:...             return other.startswith('PASS')...         except Exception:...             return False...        >>> f = Mock()>>> f('PASS and some other stuff')<Mock name='mock()' id='28717456'>>>> f('PASS more stuff')<Mock name='mock()' id='28717456'>>>> f("PASS blah blah don't care")<Mock name='mock()' id='28717456'>>>> expected_calls = [call(AnySuffix())]*3>>> f.assert_has_calls(expected_calls)

And an example of the failure mode:

>>> Mock().assert_has_calls(expected_calls)AssertionError: Calls not found.Expected: [call(<__main__.AnySuffix object at 0x1f6d750>), call(<__main__.AnySuffix object at 0x1f6d750>), call(<__main__.AnySuffix object at 0x1f6d750>)]Actual: []