使用mock patch模拟实例方法
我在测试一个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))
我哪里做错了呢?
3 个回答
7
如果你想对被模拟的方法使用 assert_called
等功能,可以使用 patch.object
,并把替代的方法放在 MagicMock(side_effect=)
中,比如:
with patch.object(class_to_mock, attribute_name, \
MagicMock(side_effect=replacement_method)) as replacement_method_mock:
例如:
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()
45
哦,我之前搞不清楚这个补丁装饰器应该放在哪里。现在已经修好了:
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))
103
在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):
https://docs.python.org/3/library/unittest.mock.html#patch-object