Python restituisce l'oggetto MagicMock invece di return_value


86

Ho un file python a.pyche contiene due classi Ae B.

class A(object):
    def method_a(self):
        return "Class A method a"

class B(object):
    def method_b(self):
        a = A()
        print a.method_a()

Vorrei unirmi method_bin classe prendendo in Bgiro A. Ecco il contenuto del file testa.pyper questo scopo:

import unittest
import mock
import a


class TestB(unittest.TestCase):

    @mock.patch('a.A')
    def test_method_b(self, mock_a):
        mock_a.method_a.return_value = 'Mocked A'
        b = a.B()
        b.method_b()


if __name__ == '__main__':
    unittest.main()

Mi aspetto di entrare Mocked Ain uscita. Ma quello che ottengo è:

<MagicMock name='A().method_a()' id='4326621392'>

Dove sto sbagliando?


1
Durante il test, A()restituisce return_valuefrom mock_A(un normale MagicMock, poiché non hai specificato nient'altro), che non è un'istanza della classe A. È necessario impostarlo return_valuein modo che abbia un valore definito method_a.
jonrsharpe

3
mock_a.method_a.return_value = 'Mocked A' => mock_a (). method_a.return_value = 'Mocked A' dovrebbe essere migliore :)
Ali SAID OMAR

@AliSAIDOMAR è esattamente corretto, è il valore restituito dalla chiamata mock_ache dovrebbe avere il metodo, non mock_ase stesso.
jonrsharpe

1
@jonrsharpe. Grazie per la tua spiegazione. Ho appena provato. Entrambi mock_a().method_a.return_value = 'Mocked A'e hanno mock_a.return_value.method_a.return_value = 'Mocked A'funzionato. Grazie mille per i tuoi commenti. Potresti, per favore, andare avanti e metterlo come risposta?
Mehdi Jafarnia Jahromi

@MehdiJafarniaJahromi grazie mille!
Niakros

Risposte:


96

Quando tu @mock.patch('a.A'), stai sostituendo la classe Anel codice sotto test con mock_a.

In B.method_bte allora imposta a = A(), che è adesso a = mock_a()- cioè aè il return_valuedi mock_a. Poiché non hai specificato questo valore, è regolare MagicMock; nemmeno questo è configurato, quindi ottieni la risposta predefinita (ancora un'altra MagicMock) quando chiami i metodi su di esso.

Invece, vuoi configurare il return_valuedimock_a per avere il metodo appropriato, cosa che puoi fare come:

mock_a().method_a.return_value = 'Mocked A' 
    # ^ note parentheses

o, forse più esplicitamente:

mock_a.return_value.method_a.return_value = 'Mocked A'

Il tuo codice avrebbe funzionato nel caso a = A(assegnando la classe, non creando un'istanza), poiché allora a.method_a()avrebbe attivato il tuo metodo fittizio.


4
Eccezionale. Hai reso la mia giornata.
Vishal

Ciao @jonrsharpe, sto usando un dataframe panda con df.columns per controllare la mia condizione if . Non usa le parentesi (cioè non è richiamabile). Cosa devo fare per restituire un elenco in questo caso. Grazie!
imsrgadich

@imsrgadich hai bisogno di una finta per questo? Basta creare il dataframe appropriato, trattarlo come un valore di prova.
jonrsharpe

@jonrsharpe sì, potrei farlo ma sto anche eseguendo df.drop nel mio metodo chiamato che devo affermare e oltre che non sto restituendo il dataframe dal metodo chiamato. Questo crea un problema. Ho trovato un modo mock_data.configure_mock(columns='my_column')che lo risolve. Grazie per la risposta però. (ref: bradmontgomery.net/blog/how-world-do-you-mock-name-attribute )
imsrgadich

Questo non sembra funzionare quando deridi due modelli SQLAlchemy nello stesso test. Il primo funziona bene, ma il secondo restituirà un MagicMock indipendentemente da ciò che definisci.
Juha Untinen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.