Unit-tests should test functionality and try to be agnostic to implementation details.
Mock.assert_called_with()
is a convenient function, yet AFAIK it compares *args
to *args
and **kwargs
to **kwargs
. Therefore:
# class to be mocked during test
class SomeClass():
def func(self,a,b,c=5):
# ...
# code under test
somaclass_instance.func(1,b=2,c=3)
# test code that works
someclass_mock.func.assert_called_with(1,b=2,c=3)
# test code that won't work
someclass_mock.func.assert_called_with(1,2,c=3)
someclass_mock.func.assert_called_with(a=1,b=2,c=3)
is there a way to generalize this so that the specifics of which *args
where used as **kwargs
in the call to func
, which is really an implementation detail, will be ignored?
Since Python 3.4, just like you wanted, asserting for specific call signatures is normalized automatically when a callable Mock is created with a spec, and for object methods when using auto-speccing.
From the very end of the documentation of the Mock class:
A callable mock which was created with a spec (or a spec_set) will introspect the specification object’s signature when matching calls to the mock. Therefore, it can match the actual call’s arguments regardless of whether they were passed positionally or by name:
>>> def f(a, b, c): pass ... >>> mock = Mock(spec=f) >>> mock(1, 2, c=3) <Mock name='mock()' id='140161580456576'> >>> mock.assert_called_with(1, 2, 3) >>> mock.assert_called_with(a=1, b=2, c=3)
This applies to assert_called_with(), assert_called_once_with(), assert_has_calls() and assert_any_call(). When Autospeccing, it will also apply to method calls on the mock object.
Changed in version 3.4: Added signature introspection on specced and autospecced mock objects.
File a feature request to mock.
Fundamental problem is that without access to real function/class mock has no way of knowing the order of keyword arguments, that is invocations call(a=1, b=2)
and call(b=2, a=1)
look identical to mock, while invocations call(1, 2)
and call(2, 1)
do not.
If you wish to generalize mock, you will need to pass a call prototype or a function in lieu of prototype, e.g:
amock.afunc.assert_called_with(1, 2, c=3, __prototype__=lambda a=None, b=None, c=None: None)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With