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

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 TestCase
from mock import Mock

from .models import Example


def 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.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)