Title: Add assert_not_called_with
Type: enhancement Stage: resolved
Components: Versions: Python 3.9
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: cjw296, lisroach, mariocj89, michael.foord, pconnell, serhiy.storchaka, valkheim, xtreak
Priority: normal Keywords:

Created on 2019-10-16 06:22 by valkheim, last changed 2019-10-28 21:27 by serhiy.storchaka. This issue is now closed.

Messages (3)
msg354770 - (view) Author: valkheim (valkheim) Date: 2019-10-16 06:22
This would be nice to integrate an assert_not_called_with feature.

I had to implement it to test a publish/subscribe patterns where multiple subscibers got called but not with the same arguments.

Here is my implementation:

def assert_not_called_with(self, *args, **kwargs):
    """assert that the mock was never called with the specified arguments.
        self.assert_called_with(*args, **kwargs)
    except AssertionError:
    raise AssertionError(
        "Expected %s to not have been called."
        % self._format_mock_call_signature(args, kwargs)

An alternative would had been to iterate the call_args_list but it wouldn't result in a clean one-line assert

coming from:
msg354811 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2019-10-16 18:18
assert_called_with only checks against the last call. The docs were have been fixed with issue35946. So after multiple calls the you might get an assertion error in your proposed implementation leading to the conclusion that the call never happened but it's just that the last call doesn't match as explained below. mock calls are recorded in mock_calls attribute so you can do a contains check by constructing the call object to see if the calls are present. For multiple calls you can do a list comprehension and use all().

If it's added it would also mean the addition of assert_not_awaited_with for AsyncMock. Given that there is contains check to do it one line I am not sure it's worthy enough to expand the API. I couldn't find any related proposals in the past. assert_not_called is also a shortcut as added in issue21262. I would wait for others opinion on this.

Python 3.9.0a0 (heads/master:392a13bb93, Oct 16 2019, 22:59:54) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from unittest.mock import Mock, call
>>> m = Mock()
>>> m(1)
<Mock name='mock()' id='140089503302176'>
>>> m(2)
<Mock name='mock()' id='140089503302176'>
>>> m.assert_called_with(1) # Raises AssertionError but the call was actually made.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/xtreak/stuff/python/cpython/Lib/unittest/", line 902, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: expected call not found.
Expected: mock(1)
Actual: mock(2)
>>> call(3) not in m.mock_calls # Use contains check instead of iterating through call_args_list
>>> call(1) not in m.mock_calls
msg354814 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-10-16 18:33
Do you know why there is assertRaises(), but there is no assertNotRaises()?

Because assertNotRaises(Exception, callable, *args, **kwargs) would be equivalent to just callable(*args, **kwargs). Call the function, and if is raised an exception, the test will fail.

Similarly, there is no need of assert_not_called_with(). Just define a function which raises an exception when it is called with the specified arguments.
Date User Action Args
2019-10-28 21:27:58serhiy.storchakasetstatus: open -> closed
resolution: rejected
stage: resolved
2019-10-28 20:48:08pconnellsetnosy: + pconnell
2019-10-16 18:33:59serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg354814
2019-10-16 18:18:52xtreaksetmessages: + msg354811
2019-10-16 06:52:17xtreaksetnosy: + cjw296, michael.foord, lisroach, mariocj89, xtreak

versions: + Python 3.9
2019-10-16 06:22:50valkheimcreate