2017-02-22 66 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, особенно если вы делаете фантазии и включаете в объект другие объекты.

 Смежные вопросы

  • Нет связанных вопросов^_^