2017-02-22 37 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,特別是如果你喜歡看東西,並在封閉物中包含其他物體。