这里有一个简单的例子来说明我的问题。
<标题>代码class Bar:
def do_a_thing(self):
print('doing a thing')
class BarSupplier:
def get_bar(self) -> Bar:
return Bar()
class Foo:
def __init__(self, bar_supplier: BarSupplier):
self.bar_supplier = bar_supplier
def do_foo(self):
self.bar_supplier.get_bar().do_a_thing()
<标题>测试from unittest import TestCase
from unittest.mock import MagicMock, call
from calls_example import Foo
class TestCallsExample(TestCase):
def test_once(self):
bar_supplier = MagicMock()
bar_supplier.get_bar.return_value = MagicMock()
foo = Foo(bar_supplier)
foo.do_foo()
bar_supplier.get_bar.assert_has_calls([
call(),
])
def test_twice(self):
bar_supplier = MagicMock()
bar_supplier.get_bar.return_value = MagicMock()
foo = Foo(bar_supplier)
foo.do_foo()
foo.do_foo()
bar_supplier.get_bar.assert_has_calls([
call(),
call()
])
<标题>结果第一个测试通过。
第二个测试失败,有以下异常:
Failure
Traceback (most recent call last):
...
AssertionError: Calls not found.
Expected: [call(), call()]
Actual: [call(), call().do_a_thing(), call(), call().do_a_thing()]
这感觉真的很奇怪的行为-我断言对bar_supplier
模拟上的get_bar
方法的调用,但随后调用列表包括对由get_bar
方法返回的不同模拟的调用。
我确信这是一个误解而不是一个错误,但是我如何才能最好地避免在我的呼叫列表中得到那些.do_a_thing()
呼叫?
这是因为.get_bar()
的相同mock总是随后调用.do_a_thing()
,如文档所示:
assert_has_calls(calls, any_order=False)
断言mock已被指定的调用调用。
mock_calls
检查列表中是否有呼叫。
其中mock_calls不仅包括对自身的调用:
mock_calls
mock_calls记录所有对模拟对象的调用,其方法,魔术方法和返回值模拟.
解决方案1
您可以使用any_order=True
设置assert_has_calls,如文档所示:
如果
any_order
为假,则调用必须顺序。在指定的调用之前或之后可以有额外的调用。如果
any_order
为真,则调用可以在任意顺序,但它们必须都出现在mock_calls中。
所以改变:
bar_supplier.get_bar.assert_has_calls([
call(),
call()
])
:
bar_supplier.get_bar.assert_has_calls([
call(),
call()
],
any_order=True)
解决方案2
另一种选择是检查call_args_list:
assert bar_supplier.get_bar.call_args_list == [
call(),
call()
]