繁体   English   中英

声明对不同模拟对象的一系列调用

[英]Assert a sequence of calls to different mock objects

如何使用Python mock库来声明对不同模拟对象的特定调用序列?

例如,我要断言:

  • 调用foo(spam, eggs) 然后
  • 称呼bar(beans, ham) 然后
  • 调用foo(sausage)

我可以修补foobar每一个,并且生成的模拟对象每个都允许我对对该模拟的调用进行断言。 但是我需要访问整个调用序列以对该序列进行断言。

是的,理想情况下,我只需要检查结果状态并在事实发生后对其进行断言。 但这在某些系统上是不可行的,并且正确状态的唯一可行描述是“这些调用是按此特定顺序进行的”。

我可以使用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()
parent_mock.attach_mock(foomock, 'foo')
parent_mock.attach_mock(barmock, 'bar')

现在您可以执行与上述相同的断言(只要您不需要保留原始模拟对象的父母...那么我不确定该告诉您什么...)

解决此问题的最初尝试是使用专门的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)

这有缺点:

  • 可能是在重新发明一个或多个轮子。 (如果您认为这样,请添加一个更好的答案。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM