python mock side_effect或return_value依赖于call_count

imo*_*lit 35 python mocking

为了测试一个轮询函数,我想模拟一个子函数的调用,这样第一次调用它就会失败,第二次调用它就会成功.这是一个非常简化的版本:

poll_function(var1):
    value = sub_function(var1)  # First call will return None
    while not value:
        time.sleep(POLLING_INTERVAL)  
        value = sub_function(var1) # A subsequent call will return a string, e.g "data"
    return value
Run Code Online (Sandbox Code Playgroud)

这可能与框架中的Mock对象有关mock吗?我知道Mock对象有一个call_count我应该可以以某种方式使用的属性.

现在我已经通过创建一个我用来修补补丁的自定义模拟对象来解决它sub_function(),但我觉得应该有一个更好的更简洁的方法:

def test_poll():
    class MyMock(object):                                                      

        def __init__(self, *args):                                             
            self.call_count = 0                                                

        def sub_function(self, *args, **kwargs):                             
            if self.call_count > 1:                                            
                return "data"            
            else:                                                              
                self.call_count += 1                                           
                return None  

    my_mock = MyMock()                                                         
    with patch('sub_function', my_mock.sub_function):           
        ok_(poll_function())         
Run Code Online (Sandbox Code Playgroud)

aqu*_*tae 57

如果我正确理解你的问题,你可以通过设置side_effect为iterable来实现.对于你的简单案例:

>>> mock_poll = Mock(side_effect=[None, 'data'])
>>> mock_poll()
None
>>> mock_poll()
'data'
Run Code Online (Sandbox Code Playgroud)

如果您想允许无限次呼叫,请使用itertools cyclechain功能:

>>> mock_poll = Mock(side_effect=chain(['first'], cycle(['others'])))
Run Code Online (Sandbox Code Playgroud)

  • 是的,谢谢,这非常有效。然而,值得注意的是,这在“模拟”版本“0.7.2”上不起作用,而这正是我当时使用的版本。我必须升级到版本“0.8.0”才能正确使用此功能。 (2认同)