21

我正在使用 Mock ( http://www.voidspace.org.uk/python/mock/mock.html ),遇到了一个我无法找出解决方案的特定模拟案例。

我有一个函数多次调用 some_function 被模拟。

def function():
    some_function(1)
    some_function(2)
    some_function(3)

我只想模拟对 some_function 的第一次和第三次调用。我想对真正的 some_function 进行第二次调用。

我尝试了一些替代方法http://www.voidspace.org.uk/python/mock/mock.html#mock.Mock.mock_calls,但没有成功。

在此先感谢您的帮助。

4

3 回答 3

27

似乎该wraps论点可能是您想要的:

wraps:要包装的模拟对象的项目。如果 wraps 不是 None 那么调用 Mock 会将调用传递给被包装的对象(返回真实结果并忽略 return_value)。

但是,由于您只希望第二次调用不被嘲笑,我建议使用mock.side_effect.

如果 side_effect 是一个可迭代对象,那么对模拟的每次调用都将返回可迭代对象的下一个值。

如果您想为每次调用返回不同的值,这是一个完美的选择:

somefunction_mock.side_effect = [10, None, 10] 

只有第一次和第三次调用somefunction会返回 10。

但是,如果您确实需要调用真正的函数,但不是第二次,您也可以传递side_effect一个可调用对象,但我觉得它非常难看(可能有更聪明的做法):

 class CustomMock(object):

     calls = 0

     def some_function(self, arg):
         self.calls += 1
         if self.calls != 2:
             return my_real_function(arg)
         else:
             return DEFAULT

somefunction_mock.side_effect = CustomMock().some_function

     
于 2013-04-01T21:15:07.887 回答
3

甚至比创建一个CustomMock类更简单:

def side_effect(*args, **kwargs):
    if side_effect.counter < 10:
        side_effect.counter += 1
        return my_real_function(arg) 
    else:
        return DEFAULT

side_effect.counter = 0
mocked_method.side_effect = side_effect
于 2018-07-30T09:55:36.927 回答
0

我今天也面临同样的情况。经过一番犹豫,我找到了一种不同的方法来解决它。

起初,我的函数如下所示:

def reboot_and_balabala(args):
    os.system('do some prepare here')
    os.system('reboot')
    sys.exit(0)

我希望调用 os.system 的第一次调用,否则不会生成本地文件,我无法验证它。但我真的不希望调用 os.system 的第二次调用,哈哈。

起初,我有一个类似于以下的单元测试:

def test_reboot_and_balabala(self):
    with patch.object(os, 'system') as mock_system:
        # do some mock setup on mock_system, this is what I looked for
        # but I do not found any easy and clear solution
        with patch.object(sys, 'exit') as mock_exit:
            my_lib.reboot_and_balabala(...)
            # assert mock invoke args
            # check generated files

但最后,我意识到,在调整代码后,我有一个更好的代码结构和单元测试,通过以下方式:

def reboot():
    os.system('reboot')
    sys.exit(0)

def reboot_and_balabala(args):
    os.system('do some prepare here')
    reboot()

然后我们可以通过以下方式测试这些代码:

def test_reboot(self):
    with patch.object(os, 'system') as mock_system:
        with patch.object(sys, 'exit') as mock_exit:
            my_lib.reboot()
            mock_system.assert_called_once_with('reboot')
            mock_exit.assert_called_once_with(0)

def test_reboot_and_balabala(self):
    with patch.object(my_lib, 'reboot') as mock_reboot:
        my_lib.reboot_and_balabala(...)
        # check generated files here
        mock_reboot.assert_called_once()

这不是问题的直接答案。但我认为这是非常鼓舞人心的。

于 2020-02-27T11:26:01.847 回答