使用模拟补丁模拟实例方法

我试图在测试一个 Django 应用程序时模仿一些东西,这个应用程序的名字很有想象力。我似乎不能让它工作,我试着这样做:

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

我做错了什么?

125139 次浏览

Ah I was confused on where to apply that patch decorator. Fixed:

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

To add onto Kit's answer, specifying a 3rd argument to patch.object() allows the mocked object/method to be specified. Otherwise, a default MagicMock object is used.

    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!

Note that, if you specify the mocking object, then the default MagicMock() is no longer passed into the patched object -- e.g. no longer:

def test_enter_promotion(self, mock_method):

but instead:

def test_enter_promotion(self):

https://docs.python.org/3/library/unittest.mock.html#patch-object

If you'd like to do assert_called etc. against the mocked method, use the patch.object and wrap replacement method in a MagicMock(side_effect=), ie:

with patch.object(class_to_mock, attribute_name, \
MagicMock(side_effect=replacement_method)) as replacement_method_mock:

eg.:

from unittest.mock import patch, MagicMock


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


def test_enter_promotion(self):
with patch.object(my_app.models.FooClass, 'bar', MagicMock(side_effect=fake_bar)) as fake_bar_mock:
self.client.get(reverse(view))
# Do something I want!
fake_bar_mock.assert_called()