Mocking a Django Queryset in order to test a function that takes a queryset Mocking a Django Queryset in order to test a function that takes a queryset python python

Mocking a Django Queryset in order to test a function that takes a queryset


Of course you can mock a QuerySet, you can mock anything.

You can create an object yourself, and give it the interface you need, and have it return any data you like. At heart, mocking is nothing more than providing a "test double" that acts enough like the real thing for your tests' purposes.

The low-tech way to get started is to define an object:

class MockQuerySet(object):    pass

then create one of these, and hand it to your test. The test will fail, likely on an AttributeError. That will tell you what you need to implement on your MockQuerySet. Repeat until your object is rich enough for your tests.


I am having the same issue, and it looks like some nice person has written a library for mocking QuerySets, it is called mock-django and the specific code you will need is here https://github.com/dcramer/mock-django/blob/master/mock_django/query.py I think you can then just patch you models objects function to return one of these QuerySetMock objects that you have set up to return something expected!


For an empty Queryset, I'd go simply for using none as keithhackbarth has already stated.

However, to mock a Queryset that will return a list of values, I prefer to use a Mock with a spec of the Model's manager. As an example (Python 2.7 style - I've used the external Mock library), here's a simple test where the Queryset is filtered and then counted:

from django.test import TestCasefrom mock import Mockfrom .models import Exampledef queryset_func(queryset, filter_value):    """    An example function to be tested    """    return queryset.filter(stuff=filter_value).count()class TestQuerysetFunc(TestCase):    def test_happy(self):        """        `queryset_func` filters provided queryset and counts result        """        m_queryset = Mock(spec=Example.objects)        m_queryset.filter.return_value = m_queryset        m_queryset.count.return_value = 97        result = func_to_test(m_queryset, '__TEST_VALUE__')        self.assertEqual(result, 97)        m_queryset.filter.assert_called_once_with(stuff='__TEST_VALUE__')        m_queryset.count.assert_called_once_with()

However, to fulfil the question, instead of setting a return_value for count, this could easily be adjusted to be a list of model instances returned from all.

Note that chaining is handled by setting the filter to return the mocked queryset:

m_queryset.filter.return_value = m_queryset

This would need to be applied for any queryset methods used in the function under test, e.g. exclude, etc.