Python mock method call arguments display the last state of a list
Unfortunately, this looks to be a shortcoming of the mock
library, and from looking at the code this doesn't look to be possible without patching the mock library itself. However, it looks like there is a fairly lightweight way to do this to get the effect you are looking for:
import copy
from mock import MagicMock
class CopyArgsMagicMock(MagicMock):
"""
Overrides MagicMock so that we store copies of arguments passed into calls to the
mock object, instead of storing references to the original argument objects.
"""
def _mock_call(_mock_self, *args, **kwargs):
args_copy = copy.deepcopy(args)
kwargs_copy = copy.deepcopy(kwargs)
return super(CopyArgsMagicMock, self)._mock_call(*args_copy, **kwargs_copy)
Then (to state the obvious) simply replace your MagicMock
with a CopyArgsMagicMock
and you should see the required behavior.
Please note that this has only been tested for the use case provided, so this may not be a complete and robust solution to the problem, but hopefully it proves useful.
For python 3.8 the accepted solution did not work anymore for me.
However, there is a solution in the official python docs:
https://docs.python.org/3/library/unittest.mock-examples.html#coping-with-mutable-arguments
You have to scroll down a bit to find the following:
An alternative approach is to create a subclass of Mock or MagicMock that copies (using copy.deepcopy()) the arguments. Here’s an example implementation:
from copy import deepcopy
class CopyingMock(MagicMock):
def __call__(self, /, *args, **kwargs):
args = deepcopy(args)
kwargs = deepcopy(kwargs)
return super(CopyingMock, self).__call__(*args, **kwargs)
This worked for me for python 3.8.