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

前端 未结 9 1278
青春惊慌失措
青春惊慌失措 2020-12-28 13:55

I have a utility function in my Django project, it takes a queryset, gets some data from it and returns a result. I\'d like to write some tests for this function. Is there a

9条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-28 14:51

    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.

提交回复
热议问题