Today I spent pretty much time on some tricky unit test issue, where I tried to properly assert two calls on the same method and getting very strange behavior from unittest.mock
's assert_has_calls
method.
Here there is very simplified example how I tried to assert some calls:
class Foo():
def __init__(self):
pass
# Method that I testing!
def bar(self, d):
# doing something with dictionary
print(d)
def baz():
f = Foo()
d = {1: 2}
# first call
f.bar(d)
# updated dictionary
d[3] = 4
# second call, after dictionary mutation
f.bar(d)
@mock.patch('foo.Foo')
def test_baz(foo_mock):
baz()
foo_mock.return_value.bar.assert_has_calls(
[
mock.call({1: 2}),
mock.call({1: 2, 3: 4})
]
)
Above very simple test (i.e. test_baz
) failing with error:
E AssertionError: Calls not found.
E Expected: [call({1: 2}), call({1: 2, 3: 4})]
E Actual: [call({1: 2, 3: 4}), call({1: 2, 3: 4})]
Reason is mutation of d
dictionary in tested method between two calls and assert_has_calls
somehow doesn't capture calls history properly, i.e. it just captures last dictionary state for all calls!
This looks to me like a bug in unittest.mock
, but maybe I'm missing something here (i.e. using test framework improperly or so)?
It's pretty trivial unit test, but I have no other way to properly assert output of tested method (otherwise test would be useless). Does anybody faced with something like this and maybe have some workaround to propose?
The only solution that I see here is to change tested code (i.e. baz
function) and create copy of mutated dictionary (d
) prior to passing to method, but I would like to avoid that because it could be pretty large.