条件模拟:如果条件匹配,则调用原始函数

时间:2015-04-10 13:17:13

标签: python mocking

如何在模拟中有条件地调用orignal方法?

在这个例子中,我只想假设bar=='x'的返回值。否则我想调用原始方法。

def mocked_some_method(bar):
    if bar=='x':
        return 'fake'
    return some_how_call_original_method(bar)

with mock.patch('mylib.foo.some_method', mocked_some_method):
    do_some_stuff()

我知道这有点奇怪。如果我想在mylib.foo.some_method方面伪造do_some_stuff(),那么它应该是无条件的。对some_method的所有(不是一些)调用都应该被嘲笑。

在我的情况下,它是一个集成测试,而不是一个微小的单元测试,mylib.foo.some_method是一种经常被使用的调度程序。在一个案例中,我需要伪造结果。

3 个答案:

答案 0 :(得分:21)

如果你只需要替换行为而不需要模拟调用断言函数,你可以使用new参数;否则你可以使用可以调用的side_effect

我猜some_method是一个对象方法(而不是staticmethod)所以你需要一个引用它的对象来调用它。您的包装器应该声明对象的第一个参数,并且您的补丁使用autospec=True来使用side_effect大小写的正确签名。

最后的技巧是保存原始方法引用并使用它来进行调用。

orig = mylib.foo.some_method
def mocked_some_method(self, bar):
    if bar=='x':
        return 'fake'
    return orig(self, bar)

#Just replace:
with mock.patch('mylib.foo.some_method', new=mocked_some_method):
    do_some_stuff()

#Replace by mock
with mock.patch('mylib.foo.some_method', side_effect=mocked_some_method, autospec=True) as mock_some_method:
    do_some_stuff()
    assert mock_some_method.called

答案 1 :(得分:1)

这里是一个示例,该示例说明如何动态修补类方法并在需要时执行原始方法

  1. 需要测试的代码
class CheckMockMethod:

    def get_value_x_10(self, value):
        """Method which is going to be patched"""
        return value*10


def wrapper_func():
    """Function which is called from test"""
    for i in [1, 2, 3]:
        print(CheckMockMethod().get_value_x_10(i))
  1. mock.patcher的ContextManager测试助手
import mock
from contextlib import contextmanager


@contextmanager
def mock_patch_method_original(mock_path, original_method, results):
    results = iter(results)

    def side_effect(self, *args, **kwargs):
        value = next(results)
        if value == '__original__':
            side_effect.self = self
            return original_method(self, *args, **kwargs)
        else:
            return value

    patcher = mock.patch(mock_path, autospec=True, side_effect=side_effect)
    yield patcher.start()
    patcher.stop()
  1. 示例测试方法,当您想返回原始值时,请查看结果var __original__的值
    from somewhere import CheckMockMethod
    from test_helpers import mock_patch_method_original


    def test_wrapper(self):
        path = '<import-path>.CheckMockMethod.get_value_x_10'
        orig = CheckMockMethod.get_value_x_10

        results = [1000, '__original__', 3000]

        with mock_patch_method_original(path, original_method=orig, results=results):
            wrapper_func()

  1. 结果

    通过模拟,您将看到

1000、20、3000

其中 1000 3000 是修补值,而 20 是原始值

答案 2 :(得分:1)

使用 return_value 或 side_effects 返回 unittest.mock.DEFAULT 将调用原始方法。这应该可以避免一些包装器。