Search code examples
pythondjangopython-2.7python-unittestpython-mock

How can I mock a method of a Django model manager?


Here is a little class (in myapp/getters.py):

from django.contrib.auth.models import User

class UserGetter:
    def get_user(self):
        return User.objects.get(username='username')

I would like to mock out the call to User.objects.get, return a MagicMock, and test that the method returns what I injected. In myapp/tests/tests_getters.py:

from unittest import TestCase
from django.contrib.auth.models import User, UserManager
from mock import patch, create_autospec
from myapp.getters import UserGetter

class MockTestCase(TestCase):
    @patch('myapp.getters.User', autospec=True)
    def test(self, user_class):
        user = create_autospec(User)
        objects = create_autospec(UserManager)
        objects.get.return_value = user
        user_class.objects.return_value = objects
        self.assertEquals(user, UserGetter().get_user())

But when I run this test (with python manage.py test myapp.tests.tests_getters) I get

AssertionError:
  <MagicMock name='User.objects().get()' spec='User' id='4354507472'> !=
    <MagicMock name='User.objects.get()' id='4360679248'>

Why do I not get back the mock I injected? How can I write this test correctly?


Solution

  • I think this is your problem:

    user_class.objects.return_value = objects
    

    You instruct the mock to have a function "objects" that returns the objects on the right side.
    But your code never calls any objects() function. It accesses the User.objects property, User is a Mock here, so User returns a new Mock on property access.