我正在编写一些单元测试,想使用Mock。
给定以下代码:
# the 'real' query set is a Django database model
# qs = SomeDjangoModel.objects.filter(name='some_name')
qs = mock.Mock()
qs.filter.return_value = qs
item = mock.Mock()
item.do_work.return_value = "Some text"
qs.iter.return_value = iter([item])
# below is the code I want to test..
qs = qs.filter(name='some name')
qs = qs.filter(valid_from__lte=Timezone.now())
for obj in qs:
obj.do_work()
运行时,我得到
类型错误:"模拟"对象不可迭代
我试过打补丁
@mock.patch('__builtin__.iter')
但我似乎无法让它工作。我还没有成功地弄清楚当查询集被 for 循环"使用"时到底发生了什么。
非常感谢帮助!
[在第一个解决方案提案之后,使用进一步添加的示例代码进行编辑]
你必须
使用iterator
和MagicMock
它__iter__
定义
from unittest.mock import Mock, MagicMock
from datetime import datetime
qs = MagicMock()
qs.filter.return_value = qs
item = Mock()
item.do_work.return_value = "Some text"
qs.iterator.return_value = iter([item])
# below is the code I want to test..
qs = qs.filter(name='some name')
qs = qs.filter(valid_from__lte=datetime.now())
for obj in qs:
obj.do_work()
通常我嘲笑QuerySet是一个列表,这似乎更容易。所以:
something.return_value = [item]
其中something
是计算查询集的函数或位置。举个实际例子:
MyModel.objects.filter.return_value = [item]
这仅在不使用 QuerySet 特定特征时才有效。
我的一位同事帮助我解决了这个问题。我想要以下代码。
def the_iter(self):
return iter(self.my_test_list)
def test_my_code(self):
qs = mock.Mock()
qs.filter.return_value = qs
the_item = mock.Mock()
the_item.do_work.return_value = "Some text"
self.my_test_list = [the_item]
qs.__iter__ = mock.Mock(side_effect=self.the_iter)
# below is the code I want to test..
qs = qs.filter(name='some name')
qs = qs.filter(colour='Yellow')
for obj in qs:
print obj.do_work()