2014-12-05 73 views
1

如何使用Python mock庫來斷言對不同模擬對象的調用的特定序列?斷言對不同模擬對象的調用序列

例如,我要斷言:

  • foo(spam, eggs)呼叫;然後
  • 電話bar(beans, ham);然後
  • 致電foo(sausage)

我可以修補每個foobar,並將得到的模擬每個對象允許我做關於調用該模擬斷言。但是我需要訪問調用的總體序列來作出關於該序列的斷言。

是的,理想情況下,我只需要檢查結果狀態,並在事實後對其進行斷言。但是對於某些系統來說這是不可行的,對正確狀態的唯一可行的描述是「這些調用是以這個特定順序進行的」。

我可以使用mock庫的哪些功能來訪問對不同對象的調用序列,並按照正確的順序斷言調用是否按預期進行?

回答

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) 

這有缺點:

  • 它可以被重新發明一個或多個車輪。 (如果你這麼認爲,請添加一個更好的答案。)
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') 

,現在你可以做同樣主張我們在上面做的(只要你不需要保留原始嘲笑的父母......然後,我不知道該怎麼告訴你。 ..)