Python gibt das MagicMock-Objekt anstelle von return_value zurück

86

Ich habe eine Python-Datei, a.pydie zwei Klassen enthält Aund 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()

Ich würde gerne method_bim Unterricht Bdurch Verspotten unittest A. Hier ist der Inhalt der Datei testa.pyfür diesen Zweck:

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

Ich erwarte, Mocked Ain die Ausgabe zu kommen. Aber was ich bekomme ist:

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

Wo mache ich falsch?

Mehdi Jafarnia Jahromi
quelle
1
Gibt beim Testen A()das return_valuefrom zurück mock_A(ein reguläres MagicMock, da Sie nichts anderes angegeben haben), das keine Instanz der Klasse ist A. Sie müssen festlegen, return_valuedass etwas definiert ist method_a.
Jonrsharpe
3
mock_a.method_a.return_value = 'Mocked A' => mock_a (). method_a.return_value = 'Mocked A' sollte besser sein :)
Ali SAID OMAR
@AliSAIDOMAR ist genau richtig, es ist der Rückgabewert vom Aufruf mock_a, der die Methode haben sollte, nicht mock_aselbst.
Jonrsharpe
1
@ Jonrsharpe. Danke für Ihre Erklärung. Ich habe es versucht. Beides mock_a().method_a.return_value = 'Mocked A'und mock_a.return_value.method_a.return_value = 'Mocked A'gearbeitet. Vielen Dank für Ihre Kommentare. Würden Sie bitte weitermachen und es als Antwort geben?
Mehdi Jafarnia Jahromi
@MehdiJafarniaJahromi vielen Dank!
Niakros

Antworten:

96

Wenn Sie @mock.patch('a.A'), ersetzen Sie die Klasse Aim zu testenden Code durch mock_a.

In B.method_bdir dann setzen a = A(), was jetzt ist a = mock_a()- dh das aist return_valuevon mock_a. Da Sie diesen Wert nicht angegeben haben, handelt es sich um einen regulären Wert MagicMock. Dies ist auch nicht konfiguriert, daher erhalten Sie die Standardantwort (noch eine andere MagicMock), wenn Sie Methoden darauf aufrufen.

Stattdessen möchten Sie konfigurieren die return_valuevonmock_a haben , die entsprechende Methode, die Sie entweder tun können:

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

oder vielleicht expliziter:

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

Ihr Code hätte in diesem Fall funktioniert a = A(Zuweisen der Klasse, keine Instanz erstellen), da dann a.method_a()Ihre Scheinmethode ausgelöst worden wäre.

Jonrsharpe
quelle
4
Genial. Du hast meinen Tag gerettet.
Vishal
Hallo @jonrsharpe, ich verwende einen Pandas-Datenrahmen mit df.columns , um meine if- Bedingung zu überprüfen . Es werden keine Klammern verwendet (dh es kann nicht aufgerufen werden). Was mache ich, um in diesem Fall eine Liste zurückzugeben? Vielen Dank!
Imsrgadich
@imsrgadich brauchst du dafür einen Mock ? Erstellen Sie einfach den entsprechenden Datenrahmen und behandeln Sie ihn als Testwert.
Jonrsharpe
@jonrsharpe Ja, das könnte ich tun, aber ich führe auch df.drop in meiner aufgerufenen Methode aus, die ich behaupten muss, und darüber hinaus gebe ich den Datenrahmen nicht von der aufgerufenen Methode zurück. Das schafft ein Problem. Ich habe einen Weg gefunden, mock_data.configure_mock(columns='my_column')der es löst. Vielen Dank für die Antwort. (Ref: bradmontgomery.net/blog/how-world-do-you-mock-name-attribute )
imsrgadich
Dies scheint nicht zu funktionieren, wenn Sie zwei SQLAlchemy-Modelle im selben Test verspotten. Der erste funktioniert einwandfrei, der zweite gibt jedoch einen MagicMock zurück, unabhängig davon, was Sie definieren.
Juha Untinen