2017-02-22 8 views
1

Angenommen ich Unit-Test methodA, definiert in der folgenden Klasse haben:Wie testen Einheit ein dekoriertes Verfahren

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 

Meine Testklasse ist wie folgt:

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 

Wenn ich den Test ausführen ich die Behauptung getroffen:

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 

Wenn ich einen Haltepunkt in dem Teststäbchen, nach dem Patchen, das ist ichsehenwurde gerade fein verspottet, aber dass methodA verweist immer noch die alte Wrapper:

(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>> 

Jede Idee, was das Problem hier?

Antwort

0

Nach dem Nachdenken habe ich eine Lösung gefunden.

Da scheint Affe Patchen nicht wirksam zu sein (und ich habe auch versucht, a few other Lösungen), grub ich in die Funktion Interna und das erwies sich als fruchtbar erwiesen.

Python 3 du Glück hast - nur die wraps Dekorateur verwenden, das eine __wrapped__ Attribut erzeugt, die wiederum die verpackte Funktion enthält. Weitere Informationen finden Sie in den verknüpften Antworten oben.

Python 2 Auch wenn Sie verwenden @wraps, keine Phantasie-Attribut wird erstellt. Allerdings müssen Sie nur feststellen, dass die Wrapper-Methode nichts als eine Schließung tut: so können Sie Ihre umschlossene Funktion in seinem func_closure Attribut finden.

Im ursprünglichen Beispiel die verpackte Funktion bei wäre: s.methodA.im_func.func_closure[0].cell_contents

Wrapping up (! Ha) Ich habe einen getWrappedFunction Helfer entlang dieser Linien, meine Tests zu erleichtern:

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

YMMV, vor allem, wenn Sie Lust haben und andere Objekte in den Verschluss einfügen.

Verwandte Themen