2011-12-20 15 views
28

Ho una seguente struttura:Come prendere in giro una funzione definita in un modulo di un pacchetto?

|-- dirBar 
| |-- __init__.py 
| |-- bar.py 
|-- foo.py 
`-- test.py 

bar.py

def returnBar(): 
    return 'Bar' 

foo.py

from dirBar.bar import returnBar 

def printFoo(): 
    print returnBar() 

test.py

from mock import Mock 

from foo import printFoo 
from dirBar import bar 

bar.returnBar = Mock(return_value='Foo') 

printFoo() 

il risultato di python test.py è Bar.

Come simulare printBar per restituirlo Foo in modo che lo printFoo lo stampi?

EDIT: Senza modificare qualsiasi altro file che test.py

risposta

16

sto cercando di indovinare che si sta per prendere in giro la funzione returnBar, si desidera utilizzare patch decorator:

from mock import patch 

from foo import printFoo 

@patch('foo.returnBar') 
def test_printFoo(mockBar): 
    mockBar.return_value = 'Foo' 
    printFoo() 

test_printFoo() 
23

Basta importare il modulo bar prima che il modulo foo e modelli è:

from mock import Mock 

from dirBar import bar 
bar.returnBar = Mock(return_value='Foo') 

from foo import printFoo 

printFoo() 

Quando si sta importando il returnBar in foo.py, si sono vincolanti il valore del modulo a una variabile denominata returnBar. Questa variabile è locale, quindi viene inserita la chiusura della funzione printFoo() quando viene importato foo - e i valori nella chiusura non possono essere aggiornati dal codice dall'esterno. Quindi, dovrebbe avere il nuovo valore (ovvero la funzione di simulazione) prima dello l'importazione di foo.

EDIT: la soluzione precedente funziona ma non è robusta poiché dipende dall'ordinare le importazioni. Non è molto ideale. Un'altra soluzione (che mi verificato dopo la prima) è importare il modulo bar in foo.py anziché soltanto importare la funzione returnBar():

from dirBar import bar 

def printFoo(): 
    print bar.returnBar() 

Ciò funzionerà perché la returnBar() è ora recuperato direttamente dal modulo bar anziché la chiusura. Quindi se aggiorno il modulo, la nuova funzione verrà recuperata.

+0

Sì, il problema era: avevo il codice così e non volevo cambiarli. Dopo una discussione su freenode # python ho deciso di rifattorizzare l'altro file (qui foo.py) quindi sarà migliore e più pulito – zalun

+0

@zalun c'è un collegamento a questa discussione? Sono curioso di questo! – brandizzi

+0

non ho idea - ho appena scoperto che non registro nulla ... – zalun

-3

Un altro modo per trattare con coloro caso è quello di utilizzare un po 'di iniezione di dipendenza.

Un modo semplice per farlo in python è quello di utilizzare la magica **kwargs:

foo.py

from dirBar.bar import returnBar 

def printFoo(**kwargs): 
    real_returnBar = kwargs.get("returnBar", returnBar) 
    print real_returnBar() 

test.py

from mock import Mock 

from foo import printFoo 
from dirBar import bar 

mocked_returnBar = Mock(return_value='Foo') 

printFoo(returnBar=mocked_returnBar) 

questo porterà ad una più testabile codice (e aumentare la modularità/riusabilità).

+2

l'idea è di non modificare nulla tranne test.py – zalun

4

Il posto migliore che ho trovato per risolvere i problemi beffardo è: http://alexmarandon.com/articles/python_mock_gotchas/

Si dovrebbe prendere in giro la funzione del modulo importato dalla classe in fase di test.

+3

il link sulle risposte sono scoraggiate, perché non riassumi cosa è documentato dalla pagina qui? – user22866

Problemi correlati