2014-08-30 24 views
9

Voglio affermare che un classmethod in una classe Python chiama un altro classmethod con un certo insieme di argomenti. Mi piacerebbe che il classmethod deriso fosse "spec -ato", quindi rileva se viene chiamato con il numero sbagliato di argomenti.Come applicare patch classmethod con autospec in una classe non bloccata?

Quando cerco il metodo di classe utilizzando patch.object(.., autospec=True, ..), il metodo di classe viene sostituito con un NonCallableMagicMock e genera un errore quando provo a chiamarlo.

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__) 

produce l'uscita:

MagicMock 
NonCallableMagicMock 

Come posso ottenere un mock spec-ed per _internal_classmethod quando la classe a cui appartiene non è preso in giro?

risposta

4

Utilizzare spec al posto di autospec e impostarlo direttamente.

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

mi dà

MagicMock 

per l'output.

+6

Questo risolve il problema di recuperare un NonCallableMagicMock, ma sfortunatamente non fornisce il comportamento di cattura della mancata corrispondenza della firma di chiamata sul classmethod deriso. Questo comportamento è importante perché protegge da test falsi che passano anche se il codice stesso è rotto, forse cambiando la firma della chiamata del metodo. Sospetto che il comportamento che sto cercando sia un "parziale autospec" e che forse il mock non supporta ancora quel genere di cose. – scanny

6

C'è una segnalazione di bug in sospeso (google code link e python bug tracker link) per risolvere questo problema. Fino a quando la correzione non viene incorporata, puoi provare quanto segue, che ha funzionato per me [Su 2.7, anche se penso che funzionerebbe anche in 3.x].

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 

Dopo la monkeypatch, si dovrebbe essere in grado di utilizzare mock.patch normalmente e hanno all'elettricità statica e di classe-metodi patchati correttamente.