【问题标题】:How to unit test a decorated method如何对装饰方法进行单元测试
【发布时间】:2017-07-12 07:53:48
【问题描述】:

假设我必须对methodA 进行单元测试,定义在以下类中:

class SomeClass(object):

    def wrapper(fun):
        def _fun(self, *args, **kwargs):
            self.b = 'Original'
            fun(self, *args, **kwargs)
        return _fun

    @wrapper
    def methodA(self):
        pass

我的测试类如下:

from mock import patch

class TestSomeClass(object):

    def testMethodA(self):
        def mockDecorator(f):
            def _f(self, *args, **kwargs):
                self.b = 'Mocked'
                f(self, *args, **kwargs)
            return _f

        with patch('some_class.SomeClass.wrapper', mockDecorator):
            from some_class import SomeClass
            s = SomeClass()
            s.methodA()
            assert s.b == 'Mocked', 's.b is equal to %s' % s.b

如果我运行测试,我会点击断言:

File "/home/klinden/workinprogress/mockdecorators/test_some_class.py", line 17, in testMethodA
    assert s.b == 'Mocked', 's.b is equal to %s' % s.b
AssertionError: s.b is equal to Original

如果我在测试中设置断点,修补后,我可以看到 wrapper 已被模拟出来就好了,但 methodA 仍然引用旧包装器:

(Pdb) p s.wrapper
<bound method SomeClass.mockDecorator of <some_class.SomeClass object at 0x7f9ed1bf60d0>>
(Pdb) p s.methodA
<bound method SomeClass._fun of <some_class.SomeClass object at 0x7f9ed1bf60d0>>

你知道这里有什么问题吗?

【问题讨论】:

    标签: python unit-testing mocking python-decorators


    【解决方案1】:

    经过深思熟虑,我找到了解决办法。

    由于猴子补丁似乎无效(我也尝试过a few other 解决方案),我深入研究了函数内部结构,结果证明是卓有成效的。

    Python 3 你很幸运 - 只需使用 wraps 装饰器,它会创建一个 __wrapped__ 属性,该属性又包含包装函数。有关详细信息,请参阅上面的链接答案。

    Python 2 即使您使用@wraps,也不会创建任何花哨的属性。 但是,您只需要意识到 wrapper 方法只做一个闭包:因此您将能够在其 func_closure 属性中找到您的包装函数。

    在原始示例中,包装函数位于:s.methodA.im_func.func_closure[0].cell_contents

    总结(哈!) 我按照这些思路创建了一个 getWrappedFunction 助手,以简化我的测试:

    @staticmethod
    def getWrappedFunction(wrapper):
        return wrapper.im_func.func_closure[0].cell_contents
    

    YMMV,尤其是当你做一些花哨的事情并在闭包中包含其他对象时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-28
      • 2021-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多