How to mock a queryset for use in a for loop in python/Mock

django, mocking, python, unit-testing

Solution

You have to use `iterator` and `MagicMock` which has `__iter__` defined

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

Problem

I am writing some unit tests and want to use Mock. Given the following code: ``` # 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() ``` when run, I get TypeError: 'Mock' object is not iterable I have tried patching ``` @mock.patch('__builtin__.iter') ``` but I just can't seem to get it to work. I haven't succeeded in figuring out what really goes on when the query set "used" by the for-loop. Help is greatly appreciated! [edited with further added example code, after first solution proposal]

Original source