Since all members of a MagicMock
instance are also MagicMock
instances, I figured I could just mock the top-level object without having to mock every single member along a chain of calls. Then I could simply ask my original mock if any of its members have been called in a certain way, like with assert_called
. When I try this, the call list does indeed see the calls to children, but what is the assert method for testing them?
For example:
from unittest.mock import MagicMock
# Mock an object
foo = MagicMock()
# Try calling a child
foo.bar().baz()
# foo clearly registers the calls to its child...
print(foo.mock_calls)
# ...but how do I assert them?
foo.bar.assert_called()
foo.bar.baz.assert_called()
This doesn't work:
$ python assert_member_calls.py
[call.bar(), call.bar().baz()]
[call.bar(), call.bar().baz()]
Traceback (most recent call last):
File "/(...)/assert_member_calls.py", line 14, in <module>
foo.bar.baz.assert_called()
File "/(...)/python3.9/unittest/mock.py", line 876, in assert_called
raise AssertionError(msg)
AssertionError: Expected 'baz' to have been called.
I know that one solution is to basically create one mock for every attribute, so in addition to foo
, also explicitly mock bar
and baz
along with their return value. But that seems needlessly tedious. If foo
is a mock then bar
, bar()
, baz
and baz()
are already automatically mocks as well. I shouldn't have to reinstatiate a new mock and patch foo.bar.baz
(which was a mock to begin with) just so I can have a handle to do mock_baz.assert_called()
. To support my thinking, clearly the call list for foo
contains call.bar().baz()
-- is there not a method that can do assert that call.bar().baz() was called
?
CodePudding user response:
You can check the propertiel called
from every mock object.
(Using unittest
, as it seems you are using), you could use the following code:
# ...but how do I assert them?
def test_called(self):
self.assertTrue(foo.bar.called)
self.assertTrue(foo.bar().baz.called)
CodePudding user response:
It's a simple mistake in your assertions. The first assertion as written is OK. But the second assertion should have been foo.bar().baz.assert_called()
, since baz is called on the return value foo.bar()
, and not directly on foo.bar
itself.
These assertions work:
foo.bar.assert_called()
foo.bar().baz.assert_called()
Other way to do the same thing:
foo.bar.assert_called()
foo.bar.return_value.baz.assert_called()