classification
Title: unittest.mock.Mocks with specs aren't aware of default arguments
Type: Stage:
Components: Library (Lib) Versions: Python 3.6, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: michael.foord Nosy List: Max Rothman, michael.foord, rhettinger
Priority: normal Keywords:

Created on 2017-06-30 17:13 by Max Rothman, last changed 2017-07-18 14:49 by Max Rothman.

Messages (6)
msg297433 - (view) Author: Max Rothman (Max Rothman) Date: 2017-06-30 17:13
For a function f with the signature f(foo=None), the following three calls are equivalent:

f(None)
f(foo=None)
f()

However, only the first two are equivalent in the eyes of unittest.mock.Mock.assert_called_with:

>>> with patch('__main__.f', autospec=True) as f_mock:
        f_mock(foo=None)
        f_mock.assert_called_with(None)
<no exception>
>>> with patch('__main__.f', autospec=True) as f_mock:
        f_mock(None)
        f_mock.assert_called_with()
AssertionError: Expected call: f()  Actual call: f(None)

This is definitely surprising to new users (it was surprising to me!) and unnecessarily couples tests to how a particular piece of code happens to call a function.
msg297434 - (view) Author: Max Rothman (Max Rothman) Date: 2017-06-30 17:14
I'd be happy to look at submitting a patch for this, but it'd be helpful to be able to ask questions of someone more familiar with unittest.mock's code.
msg297979 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2017-07-09 03:15
No need to spend time making a PR until there is a decision about whether this is something we want to do.
msg298177 - (view) Author: Michael Foord (michael.foord) * (Python committer) Date: 2017-07-11 19:04
Generally the called with asserts can only be used to match the *actual call*, and they don't determine "equivalence". 

To do it cleanly would be tricky, and adding complex code is a maintenance burden. I'm not convinced there's a massive use case - generally you want to make asserts about what your code actually does - not just check if it does something equivalent to your assert.

So I'm not enthusiastic about this.
msg298223 - (view) Author: Max Rothman (Max Rothman) Date: 2017-07-12 15:02
> Generally the called with asserts can only be used to match the *actual call*, and they don't determine "equivalence".

That's fair, but as unittest.mock stands now, it *does* check equivalence, but only partially, which is more confusing to users than either checking equivalence or not.

> I'm not convinced there's a massive use case - generally you want to make asserts about what your code actually does - not just check if it does something equivalent to your assert.

To me, making asserts about what your code actually does means not having tests fail because a function call switches to a set of equivalent but different arguments. As a developer, I care about the state in the parent and the state in the child, and I trust Python to work out the details in between. If Python treats two forms as equivalent, why shouldn't our tests?
msg298592 - (view) Author: Max Rothman (Max Rothman) Date: 2017-07-18 14:49
Hi, just wanted to ping this again and see if there was any movement.
History
Date User Action Args
2017-07-18 14:49:07Max Rothmansetmessages: + msg298592
2017-07-12 15:02:31Max Rothmansetmessages: + msg298223
2017-07-11 19:04:51michael.foordsetmessages: + msg298177
2017-07-09 03:15:19rhettingersetassignee: michael.foord

messages: + msg297979
nosy: + rhettinger
2017-07-08 00:19:11terry.reedysetnosy: + michael.foord
2017-06-30 17:14:51Max Rothmansetmessages: + msg297434
2017-06-30 17:13:29Max Rothmancreate