Использование фиктивного патча для имитации метода экземпляра

83

Я пытаюсь издеваться над чем-то при тестировании приложения Django, используя творчески названную библиотеку тестирования Mock . Кажется, я не могу заставить его работать, я пытаюсь сделать это:

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

Что я делаю неправильно?

Кит Сунде
источник
barфактически является "методом экземпляра", и его единственный параметр - self. Чтобы быть методом класса, он должен быть параметризован с помощью clsи вызывается как Promotion.foo().
cavaunpeu
Патчаемый объект необходимо цитировать следующим образом: @patch.object('my_app.models.FooClass', 'bar')
Lasma
2
@cavaunpeu - не (просто) параметризованный cls, но, что более важно (поскольку selfи clsне означает ничего особенного в python), украшенный@classmethod
dwanderson

Ответы:

69

Чтобы добавить в ответ Kit, укажите третий аргумент, patch.object()позволяющий указать фиктивный объект / метод. В противном случае используется MagicMockобъект по умолчанию .

    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!

Обратите внимание , что, если вы укажете издевательский объект, то по умолчанию MagicMock()будет больше не передается в исправленной объект - например , больше не:

def test_enter_promotion(self, mock_method):

но вместо того, чтобы:

def test_enter_promotion(self):

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

storm_m2138
источник
Я предпочитаю эту реализацию. Это более понятно, особенно для новичков в модульном тестировании.
Dorcioman
36

Ах, я был сбит с толку, где применить этот декоратор патча. Исправлена:

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))
Кит Сунде
источник
21
Где вы сейчас проводите связь между методом имитации и поддельной реализацией?
Physicalattraction
@physicalattraction, соединение осуществляется аргументом, mock_methodпереданным тестовой функции. Мне удалось использовать эту технику в одном из своих тестов. Это полезно, когда вы хотите только проверить, был ли вызван фиктивный метод.
Калян Ведала
@ rcode74: Как исправить метод экземпляра (некоторого другого объекта) внутри метода тестирования. например: def my_method_to_be_tested (...): r = some_script.some_class (...); r.how_to_patch_this_method.
imsrgadich
1
@imsrgadich, вы бы сделали что-то вроде r.how_to_patch_this_method = MagicMock (). Вы можете проверить документацию MagicMock, чтобы узнать, как назначить поведение фиктивному объекту.
Калян Ведала