python monkey通过装饰器在函数内修补对象的方法

时间:2017-04-21 02:33:37

标签: python mocking monkeypatching

我正在尝试学习一些高级装饰器用法。具体来说,我试图通过函数中的装饰器来修补类的方法。

这是一个基本的例子来说明我尝试做的事情。我有一个函数 ground.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: (scene?.size.width)!, height: ("specify your height")) 可以做一些事情;在那个函数中,有一个类的实例。那个例子我想要补丁。

something

我尝试尝试使用from functools import update_wrapper class Foobar: def get_something(self): return "apple" class FakeFoobar: def get_something(self): return "orange" class my_decorator: def __init__(self, original_function): self._original_function = original_function update_wrapper(self, original_function) def __call__(self, *args, **kwargs): # some magic here? return self._original_function(*args, **kwargs) @my_decorator def something(): f = Foobar() return f.get_something() if __name__ == '__main__': print(something()) Foobar进行1对1替换,或尝试使用猴子补丁FakeFoobar' Foobar方法到get_something的{​​{1}}方法。

当我运行上面的代码时,我得到以下内容:

FakeFoobar

我想找到一些方法来增强get_something的{​​{1}}方法,以便我们得到以下输出:

>>> something()
'apple'
>>>

Foobar库中有一个get_something模块,但是,我不清楚如何将其用于我的用例。我和>>> something() 'orange' >>> 函数的许多例子显示的不是将参数传递给装饰器或额外参数到mock函数的想法。

我还注意到mock正在完成类似于我尝试做的事情。我尝试深入研究源代码,但对于我尝试做的事情来说,这似乎相当复杂。

1 个答案:

答案 0 :(得分:0)

如何更新函数的全局变量dict?

from functools import update_wrapper

class Foobar:
    def get_something(self):
        return "apple"

class FakeFoobar:
    def get_something(self):
        return "orange"

class my_decorator:
    def __init__(self, original_function):
        self._original_function = original_function
        update_wrapper(self, original_function)

    def __call__(self, *args, **kwargs):
        f = self._original_function
        restore_val = f.func_globals['Foobar']
        f.func_globals['Foobar'] = f.func_globals['FakeFoobar']
        # ^^^^^ This is your magic-line.
        try:
            return f(*args, **kwargs)
        except:
            raise
        finally:
            f.func_globals['Foobar'] = restore_val

@my_decorator
def something():
    f = Foobar()
    return f.get_something()

if __name__ == '__main__':
    print(something())   #Prints orange
    print(Foobar().get_something()) #Prints apple