Verwenden eines Mock-Patches zum Verspotten einer Instanzmethode

83

Ich versuche, etwas zu verspotten, während ich eine Django-App mit der fantasievollen Mock-Testbibliothek teste . Ich kann es nicht ganz zum Laufen bringen, ich versuche das zu tun:

models.py

from somelib import FooClass

class Promotion(models.Model):
    foo = models.ForeignKey(FooClass)
    def bar(self):
       print "Do something I don't want!"


test.py

class ViewsDoSomething(TestCase):
    view = 'my_app.views.do_something'

    def test_enter_promotion(self):
        @patch.object(my_app.models.FooClass, 'bar')
        def fake_bar(self, mock_my_method):
            print "Do something I want!"
            return True

        self.client.get(reverse(view))

Was mache ich falsch?

Kit Sunde
quelle
barist in der Tat eine "Instanzmethode" und ihr einziger Parameter ist self. Um eine Klassenmethode zu sein, müsste sie mit parametriert clswerden und kann als aufgerufen werden Promotion.foo().
Cavaunpeu
Patchbares Objekt muss wie @patch.object('my_app.models.FooClass', 'bar')
folgt
2
@cavaunpeu - nicht (nur) parametrisiert mit cls, aber was noch wichtiger ist (da selfund clsnichts Besonderes in Python bedeuten), dekoriert mit@classmethod
dwanderson

Antworten:

69

Um die Antwort von Kit zu ergänzen, geben Sie ein drittes Argument an, damit patch.object()das verspottete Objekt / die verspottete Methode angegeben werden kann. Andernfalls wird ein Standardobjekt MagicMockverwendet.

    def fake_bar(self):
        print "Do something I want!"
        return True

    @patch.object(my_app.models.FooClass, 'bar', fake_bar)
    def test_enter_promotion(self):
        self.client.get(reverse(view))
        # Do something I want!

Beachten Sie, dass, wenn Sie das spöttische Objekt angeben, wird der Standard MagicMock()ist nicht mehr in das gepatchte Objekt übergeben - zum Beispiel nicht mehr:

def test_enter_promotion(self, mock_method):

aber stattdessen:

def test_enter_promotion(self):

http://www.voidspace.org.uk/python/mock/patch.html#patch-object

Storm_m2138
quelle
Ich bevorzuge diese Implementierung. Es ist klarer, insbesondere für Anfänger im Unit Testing.
Dorcioman
36

Ah, ich war verwirrt, wo ich diesen Patch-Dekorateur anwenden sollte. Fest:

class ViewsDoSomething(TestCase):
    view = 'my_app.views.do_something'

    @patch.object(my_app.models.FooClass, 'bar')
    def test_enter_promotion(self, mock_method):
        self.client.get(reverse(view))
Kit Sunde
quelle
20
Wo stellen Sie jetzt die Verbindung zwischen der Methode zum Verspotten und der gefälschten Implementierung her?
körperliche
@physicalattraction wird die Verbindung durch das mock_methodan die Testfunktion übergebene Argument hergestellt . Ich konnte diese Technik in einem meiner Tests anwenden. Dies ist nützlich, wenn Sie nur überprüfen möchten, ob die verspottete Methode aufgerufen wurde.
Kalyan Vedala
@ rcode74: So patchen Sie eine Methode einer (einer anderen Objekt-) Instanz innerhalb der Testmethode. Beispiel: def my_method_to_be_tested (...): r = some_script.some_class (...); r.how_to_patch_this_method.
Imsrgadich
1
@imsrgadich, du würdest so etwas wie r.how_to_patch_this_method = MagicMock () machen. In der MagicMock-Dokumentation können Sie sehen, wie Sie dem Scheinobjekt Verhalten zuweisen.
Kalyan Vedala