如何使用Python mock
库来断言对不同模拟对象的特定调用序列?
例如,我想断言:
foo(spam, eggs)
;然后bar(beans, ham)
;然后foo(sausage)
。我可以修补foo
和bar
中的每一个,并且生成的模拟对象每个都允许我对该模拟的调用进行断言。但我需要访问整个序列的调用来对该序列进行断言。
是的,理想情况下,我只需要检查结果状态并在事后做出断言。但是对于某些系统来说这是不可行的,并且正确状态的唯一可行描述是“这些调用是按照这个特定的顺序进行的”。
我可以使用mock
库的哪些功能来访问对不同对象的一系列调用,并按照正确的顺序断言调用?
答案 0 :(得分:1)
Mock实际上提供了类似内置的东西。模拟经常有父模拟......例如
somemock.foo # parent is somemock
父模型不会直接暴露在模拟API中,但是对子项的调用是在父模式上注册的。
import mock
m = mock.Mock()
m.a('hello world')
m.b('goodbye world')
m.c('kittens!')
m.a('Howdy')
m.assert_has_calls([
mock.call.a('hello world'),
mock.call.b('goodbye world'),
mock.call.c('kittens!'),
mock.call.a('Howdy')
]) # passes silently
m.assert_has_calls([
mock.call.a('hello world'),
mock.call.b('goodbye world'),
mock.call.a('Howdy'),
mock.call.c('kittens!')
]) # Error
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# File "/usr/local/lib/python2.7/dist-packages/mock.py", line 863, in assert_has_calls
# 'Actual: %r' % (calls, self.mock_calls)
# AssertionError: Calls not found.
# Expected: [call.a('hello world'), call.b('goodbye world'), call.a('Howdy'), call.c('kittens!')]
# Actual: [call.a('hello world'),
# call.b('goodbye world'),
# call.c('kittens!'),
# call.a('Howdy')]
但是,“我的嘲笑并非都来自同一个父母”,你可能会说。一切都还没有丢失!您可以创建父级并在事后将其附加到父级。
parent_mock = mock.Mock()
mock.attach_mock(foomock, 'foo')
mock.attach_mock(barmock, 'bar')
现在你可以做我们上面做的那种断言(只要你不需要保留原来的嘲笑父母......那么我不知道该告诉你什么......)< / p>
答案 1 :(得分:0)
解决这个问题的初步尝试是使用专门的Mock
子类,它在所提供的序列对象中注册调用,该对象可以是您喜欢的任何共享序列。
from copy import deepcopy
import mock
class CallRegisterMock(mock.MagicMock):
""" A mock object that registers each call. """
def __init__(self, call_register, *args, **kwargs):
super(CallRegisterMock, self).__init__(*args, **kwargs)
self.call_register = call_register
def __call__(self, *args, **kwargs):
args = deepcopy(args)
kwargs = deepcopy(kwargs)
call = mock.call(*args, **kwargs)
qualified_call = (self, call)
self.call_register.append(qualified_call)
super(CallRegisterMock, self).__call__(*args, **kwargs)
这有缺点: