2013-08-12 9 views
33

È possibile simulare un valore di ritorno di una funzione chiamata all'interno di un'altra funzione che sto provando a testare? Mi piacerebbe che il metodo mocked (che verrà chiamato in molti metodi che sto testando) restituisca le mie variabili specificate ogni volta che viene chiamato. Ad esempio:Utilizzo di python's mock patch.object per modificare il valore di ritorno di un metodo chiamato all'interno di un altro metodo

class Foo: 
    def method_1(): 
     results = uses_some_other_method() 
    def method_n(): 
     results = uses_some_other_method() 

e nel test di unità, che vorrebbe utilizzare finto per modificare il valore di ritorno di uses_some_other_method() modo che ogni volta si è detto in Foo, restituirà quello che definito in @patch.object(...)

risposta

53

Ci sono due modi per farlo; con la zona e con patch.object

Patch presuppone che non sta importando direttamente l'oggetto, ma che viene utilizzato dall'oggetto si sta testando come il seguente

#foo.py 
def some_fn(): 
    return 'some_fn' 

class Foo(object): 
    def method_1(self): 
     return some_fn() 

#bar.py 
import foo 
class Bar(object): 
    def method_2(self): 
     tmp = foo.Foo() 
     return tmp.method_1() 

#test_case_1.py 
import bar 
from mock import patch 

@patch('foo.some_fn') 
def test_bar(mock_some_fn): 
    mock_some_fn.return_value = 'test-val-1' 
    tmp = bar.Bar() 
    assert tmp.method_2() == 'test-val-1' 
    mock_some_fn.return_value = 'test-val-2' 
    assert tmp.method_2() == 'test-val-2' 

Se importate direttamente modulo da testare, è possibile utilizzare patch.object come segue:

#test_case_2.py 
import foo 
from mock import patch 

@patch.object(foo, 'some_fn') 
def test_foo(test_some_fn): 
    test_some_fn.return_value = 'test-val-1' 
    tmp = foo.Foo() 
    assert tmp.method_1() == 'test-val-1' 
    test_some_fn.return_value = 'test-val-2' 
    assert tmp.method_1() == 'test-val-2' 

In entrambi i casi some_fn sara 'non-deriso' dopo che la funzione di test è completo.

Edit: Per deridere molteplici funzioni, basta aggiungere altri decoratori alla funzione e aggiungere argomenti da prendere nei parametri extra

@patch.object(foo, 'some_fn') 
@patch.object(foo, 'other_fn') 
def test_foo(test_other_fn, test_some_fn): 
    ... 

Nota che quanto più il decoratore è alla definizione di funzione, il prima è nella lista dei parametri.

+1

Grazie per la spiegazione della differenza tra patch e patch.object. –

+0

come 'patch.object' due funzioni all'interno della stessa classe? –

+0

@JacksonTale ha aggiornato la risposta. – Silfheed

5

si può fare con qualcosa di simile:

#foo.py 
class Foo: 
    def method_1(): 
     results = uses_some_other_method() 

#testing.py 
form mock import patch 

@patch('Foo.uses_some_other_method'): 
def test_some_other_method(mock_some_other_method): 
    mock_some_other_method.return_value = "specific_value" 
    foo = Foo() 
    the_value = foo.method_1() 
    assert name == "specific_value" 

Ecco una fonte che si può leggere: Patching in the wrong place

4

Permettetemi di chiarire di cosa state parlando: volete testare Foo in un banco di prova, che chiama il metodo esterno uses_some_other_method. Invece di chiamare il metodo attuale, si desidera prendere in giro il valore restituito.

class Foo: 
    def method_1(): 
     results = uses_some_other_method() 
    def method_n(): 
     results = uses_some_other_method() 

Ok, supponiamo che il codice di cui sopra è in foo.py, uses_some_other_method è definita nel modulo bar.py. Ecco l'unittest:

import unitest 
import mock 

from foo import Foo 


class TestFoo(unittest.TestCase): 

    def setup(self): 
     self.foo = Foo() 

    @mock.patch('foo.uses_some_other_method') 
    def test_method_1(self, mock_method): 
     mock_method.return_value = 3 
     self.foo.method_1(*args, **kwargs) 

     mock_method.assert_called_with(*args, **kwargs) 

Se si desidera modificare il valore di ritorno ogni volta che avete passato in diverse arguements, mock fornisce side_effect.

Problemi correlati