2017-02-22 36 views
1

假设我有单元测试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>> 

的问题是在这里什么你知道吗?

回答

0

经过思考,我发现了一个解决方案。

由于猴子补丁似乎不是有效的(我也试过a few other解决方案),我深入到函数内部,并且证明是有成效的。

的Python 3 你是幸运的 - 只使用wraps装饰,它创建了一个__wrapped__属性,又包含了包装的函数。查看上面链接的答案以获取更多详细信息

Python 2 即使您使用@wraps,也不会创建任何花哨的属性。 但是,您只需要认识到包装器方法除了关闭之外什么也不做:所以您将能够在其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,特别是如果你喜欢看东西,并在封闭物中包含其他物体。