Używanie mock patch do mockowania metody instancji

83

Próbuję coś wyszydzić podczas testowania aplikacji Django przy użyciu pomysłowo nazwanej biblioteki testowej Mock . Nie wydaje mi się, żeby to działało, próbuję to zrobić:

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

Co ja robię źle?

Kit Sunde
źródło
barjest w rzeczywistości „metodą instancji”, a jej jedynym parametrem jest self. Aby być metodą klasową, musiałaby być sparametryzowana clsi można ją wywołać jako Promotion.foo().
cavaunpeu
Obiekt patchowalny należy cytować w następujący sposób: @patch.object('my_app.models.FooClass', 'bar')
Lasma
2
@cavaunpeu - nie (tylko) sparametryzowany cls, ale co ważniejsze (ponieważ selfi clsnie oznacza nic specjalnego w Pythonie), ozdobiony@classmethod
dwanderson

Odpowiedzi:

69

Aby dodać do odpowiedzi Kita, określenie trzeciego argumentu patch.object()pozwala określić mockowany obiekt / metodę. W przeciwnym razie MagicMockużywany jest obiekt domyślny .

    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!

Zauważ, że jeśli podasz obiekt szyderczy, a następnie domyślny MagicMock()jest już przeszedł do poprawionych obiektu - na przykład już nie:

def test_enter_promotion(self, mock_method):

lecz:

def test_enter_promotion(self):

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

burza_m2138
źródło
Wolę tę realizację. Jest to bardziej przejrzyste, zwłaszcza dla początkujących w testowaniu jednostkowym.
Dorcioman,
36

Ach, nie wiedziałem, gdzie zastosować ten dekorator. Naprawiony:

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
źródło
21
Gdzie teraz tworzysz połączenie między metodą mock a fałszywą implementacją?
fizyczne
@physicalattraction, połączenie jest nawiązywane przez argument mock_methodprzekazany do funkcji testowej. Udało mi się zastosować tę technikę w jednym z moich testów. Jest to przydatne tylko wtedy, gdy chcesz sprawdzić, czy została wywołana fałszywa metoda.
Kalyan Vedala
@ rcode74: Jak załatać metodę instancji (innego obiektu) wewnątrz metody testowej. np .: def my_method_to_be_tested (...): r = some_script.some_class (...); r.how_to_patch_this_method.
imsrgadich,
1
@imsrgadich, zrobiłbyś coś takiego jak r.how_to_patch_this_method = MagicMock (). Możesz sprawdzić dokumentację MagicMock, aby zobaczyć, jak przypisać zachowanie do obiektu pozorowanego.
Kalyan Vedala,