UnitTest Python模拟只有一个函数多次调用

bsl*_*ima 13 python unit-testing mocking

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

我有一个函数,多次调用some_function正在被模拟.

def function():
    some_function(1)
    some_function(2)
    some_function(3)
Run Code Online (Sandbox Code Playgroud)

我只想嘲笑some_function的第一次和第三次调用.第二个电话我想成为真正的some_function.

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

在此先感谢您的帮助.

小智 19

似乎这个wraps论点可能是你想要的:

wrap:要包装的模拟对象的项.如果wrap不是None,则调用Mock会将调用传递给包装对象(返回实际结果并忽略return_value).

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

如果side_effect是一个可迭代的,那么对mock的每次调用都将返回iterable中的下一个值.

如果您想为每个呼叫返回不同的值,那么它非常适合:

somefunction_mock.side_effect = [10, None, 10] 
Run Code Online (Sandbox Code Playgroud)

只有第一次和第三次通话somefunction才会返回10.

但是,如果你确实需要调用真正的函数,但不是第二次side_effect调用它,你也可以传递一个可调用的函数,但我觉得它很难看(可能会更聪明):

 class CustomMock(object):

     calls = 0

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

somefunction_mock.side_effect = CustomMock().some_function
Run Code Online (Sandbox Code Playgroud)


fal*_*ino 6

比创建一个类还要简单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
Run Code Online (Sandbox Code Playgroud)

  • 我发现 `my_real_function` 需要使用别名,如 `import my_real_function as someother_name` 中那样,否则 `side_effect` 函数将继续在无限递归中被调用。 (2认同)