如何断言成员调用?



因为MagicMock实例的所有成员也是MagicMock实例,所以我认为我可以只模拟顶级对象,而不必沿着调用链模拟每个成员。然后我可以简单地询问我的原始mock是否有任何成员以某种方式被调用,就像assert_called一样。当我尝试这样做时,调用列表确实看到了对子对象的调用,但是测试它们的assert方法是什么呢?

例如:

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()

这行不通:

$ 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.

我知道一个解决方案是基本上为每个属性创建一个模拟,因此除了foo之外,还显式地模拟barbaz及其返回值。但这似乎是不必要的乏味。如果foo是模拟,那么barbar()bazbaz()也已经是自动模拟了。我不应该恢复一个新的模拟和补丁foo.bar.baz(这是一个模拟开始),以便我可以有一个处理mock_baz.assert_called()的句柄。为了支持我的想法,显然foo的调用列表包含call.bar().baz()——是否没有可以执行assert that call.bar().baz() was called的方法?

这是你断言中的一个简单错误。所写的第一个断言是正确的。但是第二个断言应该是foo.bar().baz.assert_called(),因为baz是在返回值foo.bar()上调用的,而不是直接在foo.bar上调用。

这些断言有效:

foo.bar.assert_called()
foo.bar().baz.assert_called()

做同样事情的另一种方法:

foo.bar.assert_called()
foo.bar.return_value.baz.assert_called()

可以从每个模拟对象检查属性called。(使用unittest,似乎你正在使用),你可以使用以下代码:

# ...but how do I assert them?
def test_called(self):
self.assertTrue(foo.bar.called)
self.assertTrue(foo.bar().baz.called)

最新更新