Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 条件模拟:如果条件不匹配,则调用原始函数_Python_Mocking - Fatal编程技术网

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

Python 条件模拟:如果条件不匹配,则调用原始函数,python,mocking,Python,Mocking,如何在模拟中有条件地调用原始方法 在这个例子中,我只想在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

如何在模拟中有条件地调用原始方法

在这个例子中,我只想在
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()
    
我知道这有点奇怪。如果我想在
do\u stuff()中伪造
mylib.foo.some\u方法,它应该是无条件的。对
some\u方法
的所有(而不是一些)调用都应该模拟

在我的例子中,它是一个集成测试,而不是一个小型单元测试和
mylib.foo。一些方法是一种经常使用的分派器。有一次我需要伪造结果

更新
我四年前写过这个问题。今天,做有条件的嘲弄感觉很奇怪。模拟应该只在测试中使用。测试(和生产代码)应该简单且小。测试应该是无条件的。在我写这个问题时,我们仍然使用大量的生产方法和长时间的测试。今天,我遵循这些规则(简单方法、无条件测试…)。我把我的发现写了下来:

如果你只需要替换行为而不关心mock的assert函数调用,你可以使用
新的
参数;否则,您可以使用该选项进行调用

我猜
some_method
是一个对象方法(而不是
staticmethod
),因此您需要一个引用来调用它的对象。包装器应该声明对象和修补程序使用
autospec=True
作为第一个参数,以便为
副作用
案例使用正确的签名

最后一个技巧是保存原始方法引用并使用它进行调用

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

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

  • 需要测试的代码
  • mock.patcher的ContextManager测试助手
  • 示例测试方法,当您想要返回原始值时,请参见results var的值,
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuu
  • 从某处导入checkmock方法
    从测试助手导入模拟补丁方法
    def测试_包装(自):
    path='.CheckMockMethod.get_value_x_10'
    orig=CheckMockMethod.get_value_x_10
    结果=[1000',原始值,3000]
    使用模拟修补方法原始(路径,原始方法=原始,结果=结果):
    包装器_func()
    
  • 结果

    用mock你会看到

  • 1000,20,3000


    其中10003000是修补值,20是原始值

    这里的“静态”是什么意思:“我猜某些方法不是静态的…”你是对的。mock-as-wrapper不是最佳实践。我更新了问题以反映这一点。@guettli从您的问题中,我可以猜测
    某些方法
    不是
    @staticmethod
    ,而是对象方法。。。。我将通过删除旁注来更改我的答案,但它应该已经符合您的要求。链接[我的编程指南]已断开。@oszkar我更新了链接。谢谢你的提示。
    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))
    
    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()
    
        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()