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.