我正在尝试测试一个大型的旧版Django应用程序,但由于从未在大型Python应用程序上工作过,我对Python模拟感到困惑。
具体来说,我的方法内部有一条很长的调用链,可以生成一个数组:
def update(self): # in some class X
# ...
for z in foo.models.Bar.objects.filter(x=1).select('xyz'):
raise Exception("mocked successfully")
我想嘲笑foo.models.Bar.objects.filter(x=1).select('xyz')
。
尝试1
我尝试了从各种问题中收集的几种方法,特别是使用装饰器:
@mock.patch('foo.models.Bar.objects.filter.select')
def test_update(self, mock_select):
mock_select.return_value = [None]
X().update()
我从没打过模拟呼叫的内部,但是-由于引发异常,测试应该失败。
尝试2
@mock.patch('foo.models.Bar')
def test_update(self, mock_Bar):
mock_Bar.objects.filter(x=1).select('xyz').return_value = [None]
X().update()
尝试3
@mock.patch('foo.models.Bar')
def test_update(self, mock_Bar):
mock_Bar.objects.filter().select().return_value = [None]
X().update()
尝试4
然后,我尝试了一些更基本的方法,以查看是否可以获得NPE,但该方法也不起作用。
@mock.patch('foo.models.Bar')
def test_update(self, mock_Bar):
mock_Bar.return_value = None
X().update()
我所有的尝试都通过了测试,而不是像我期望的那样触发异常。
太晚了,所以我想我必须在所看到的示例中忽略一些基本知识!?
答案 0 :(得分:1)
我能够通过嘲笑对象来传递它。尝试3即将结束,您只需将其更改为filter.return_value.select.return_value
即可通过。这是我的建议,但似乎嘲笑.objects
是首选方式。
@mock.patch('foo.models.Bar.objects')
def test_update(self, mock_bar_objects):
mock_bar_objects.filter.return_value.select.return_value = [None]
X().update()
编辑:测试运行输出:
ERROR: test_update (test_x.TestDjango)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/wholevinski/.virtualenvs/p2/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
return func(*args, **keywargs)
File "/home/wholevinski/so_test/django_mock/test/test_x.py", line 10, in test_update
X().update()
File "/home/wholevinski/so_test/django_mock/foo/x_module.py", line 6, in update
raise Exception("mocked successfully")
Exception: mocked successfully
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (errors=1)