check unittest.mock call arguments agnostically w.r.t. whether they have been passed as positional arguments or keyword arguments

我是研究僧i 提交于 2021-02-18 11:08:05

问题


When a unittest.mock.Mock object has been called, I can check for the argument values with the exact signature of the call:

from unittest.mock import Mock

m = Mock()  # creation of mock
m('foo', bar='baz')  # call to the mock
m.assert_called_once_with('foo', bar='baz')  # check call arguments

Checking for a different signature with the same values will fail. E.g., if we check with 'baz' as a positional argument instead of a named argument, the assertion will fail:

m.assert_called_once_with('foo', 'baz')
# AssertionError: Expected call: mock('foo', 'baz')
# Actual call: mock('foo', bar='baz')

It has to. If the function replaced by m was

def actual_fu(foo, bar):
    # do something

then the calls would be equivalent, but if it was

def a_different_actual_fu(foo, *args, bar='some default'):
    # do something

then the calls would not be equivalent. Mock doesn't know the actual function's signature, so it can't rely on the equivalence we would have in the first case.

Is there a way of checking the call argument values that is agnostic about whether they were passed positionally or as keyword arguments, by letting the Mock (or an assertion helper function or similar) know about the actual function replaced by the mock?

The Mock object can be made aware of the object it replaces (which can be a function or method) with the optional spec argument or with autospeccing, but those serve a different purpose (limiting what calls to allow on the mock) and don't affect after-the-fact checking.


回答1:


The Mock object can be made aware of the object it replaces (which can be a function or method) with the optional spec argument or with autospeccing, but those serve a different purpose..

This is exactly what Issue 17015: mock could be smarter and inspect the spec's signature improvement issue was about. The spec actually is very much related and now makes the mock function-signature-aware.

See how mock fails when we assert mock was called with a keyword argument - without letting it know about the actual function signature:

>>> from unittest.mock import Mock
>>>
>>> def actual_fu(foo, bar):
...     pass
>>>
>>> m = Mock()
>>> m('foo', bar='baz')
<Mock name='mock()' id='4356741496'>
>>>
>>> m.assert_called_once_with(foo='foo', bar='baz')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/unittest/mock.py", line 803, in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/unittest/mock.py", line 792, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: Expected call: mock(bar='baz', foo='foo')
Actual call: mock('foo', bar='baz')

And now, see how it all passes if we provide a spec:

>>> m = Mock(spec=actual_fu)
>>> m('foo', bar='baz')
<Mock name='mock()' id='4356249528'>
>>> 
>>> m.assert_called_once_with(foo='foo', bar='baz')
>>> m.assert_called_once_with('foo', bar='baz')
>>> m.assert_called_once_with(bar='baz', foo='foo')
>>> m.assert_called_once_with('foo', 'baz')
>>>

(Used Python 3.5.1)



来源:https://stackoverflow.com/questions/34945206/check-unittest-mock-call-arguments-agnostically-w-r-t-whether-they-have-been-pa

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!