2014-08-30 11 views
9

Ich möchte behaupten, dass eine Klassenmethode in einer Python-Klasse eine andere Klassenmethode mit einem bestimmten Satz von Argumenten aufruft. Ich möchte, dass die verspottete Klassenmethode "spezifiziert" wird, also erkennt sie, ob sie mit der falschen Anzahl von Argumenten aufgerufen wird.Wie patch Klassenmethode mit Autospec in nicht angehängten Klasse?

Wenn ich die Klassenmethode mit patch.object(.., autospec=True, ..) patche, wird die Klassenmethode durch eine NonCallableMagicMock ersetzt und löst einen Fehler, wenn ich versuche, es aufzurufen.

from mock import patch 

class A(object): 

    @classmethod 
    def api_meth(cls): 
     return cls._internal_classmethod(1, 2, 3) 

    @classmethod 
    def _internal_classmethod(cls, n, m, o): 
     return sum(n, m, o) 

with patch.object(A, '_internal_classmethod') as p: 
    print(type(p).__name__) 

with patch.object(A, '_internal_classmethod', autospec=True) as p: 
    print(type(p).__name__) 

erzeugt die Ausgabe:

MagicMock 
NonCallableMagicMock 

Wie kann ich einen spec-ed Mock für _internal_classmethod bekommen, wenn die Klasse nicht verspottet wird, gehört?

Antwort

4

Anstelle von autospecspec verwenden und direkt einstellen.

with patch.object(A, '_internal_classmethod', spec=A._internal_classmethod) as p: 
    print(type(p).__name__) 

gibt mir

MagicMock 

für die Ausgabe.

+6

Dies löst das Problem, ein NonCallableMagicMock zurück zu bekommen, aber leider nicht das Verhalten des Auffangens der Call Signature Mismatch auf die mocked Klassenmethode. Dieses Verhalten ist wichtig, da es vor verspotteten Tests schützt, die bestehen, obwohl der Code selbst fehlerhaft ist, möglicherweise durch Ändern der Aufrufsignatur der Methode. Ich vermute, dass das Verhalten, nach dem ich suche, eine "teilweise Autospez" ist und dass vielleicht Spott diese Art von Dingen noch nicht unterstützt. – scanny

6

Es gibt einen hervorragenden Fehlerbericht (google code link und python bug tracker link) um dieses Problem zu beheben. Bis das Update inkorporiert wird, können Sie folgendes versuchen, was bei mir funktioniert hat [On 2.7, obwohl ich denke, dass es auch in 3.x funktionieren würde].

def _patched_callable(obj): 
    "Monkeypatch to allow autospec'ed classmethods and staticmethods." 
    # See https://code.google.com/p/mock/issues/detail?id=241 and 
    # http://bugs.python.org/issue23078 for the relevant bugs this 
    # monkeypatch fixes 
    if isinstance(obj, type): 
     return True 
    if getattr(obj, '__call__', None) is not None: 
     return True 
    if (isinstance(obj, (staticmethod, classmethod)) 
     and mock._callable(obj.__func__)): 
     return True 
    return False 
_patched_callable._old_func = mock._callable 
mock._callable = _patched_callable 

Nach dem monkeypatch, sollten Sie in der Lage sein mock.patch normal zu verwenden und richtig gepatcht statische- und Klasse-Methoden.