Mocking A RelatedManager In Django 2
This question is directly related to this question, but that one is now outdated it seems. I am trying to test a view without having to access the database. To do that I need to Mo
Solution 1:
You'll need to mock the return value of the create_reverse_many_to_one_manager
factory function. Example:
def test_valid(mocker):
mgr = mocker.MagicMock()
mocker.patch(
'django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager',
return_value=mgr
)
user = user_factory.build()
user.id = 1
...
mgr.assert_called()
Beware that the above example will mock the rev manager for all models. If you need a more fine-grained approach (e.g. patch User.auth_token
's rev manager only, leave the rest unpatched), provide a custom factory impl, e.g.
def test_valid(mocker):
mgr = mocker.MagicMock()
factory_orig = related_descriptors.create_reverse_many_to_one_manager
def my_factory(superclass, rel):
if rel.model == User and rel.name == 'auth_token_set':
return mgr
else:
return factory_orig(superclass, rel)
mocker.patch(
'django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager',
my_factory
)
user = user_factory.build()
user.id = 1
...
mgr.assert_called()
Solution 2:
I accomplish this doing this(Django 1.11.5)
@patch("django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager")
def test_reverse_mock_count(self, reverse_mock):
instance = mommy.make(DjangoModel)
manager_mock = MagicMock
count_mock = MagicMock()
manager_mock.count = count_mock()
reverse_mock.return_value = manager_mock
instance.related_manager.count()
self.assertTrue(count_mock.called)
hope this help!
Solution 3:
If you use django's APITestCase
, this becomes relatively simple.
class TestChangeEmail(APITestCase):
def test_valid(self):
user = UserFactory()
auth_token = AuthToken.objects.create(user=user)
response = self.client.post(
reverse('your endpoint'),
data={'email': 'foo@example.com'}
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(AuthToken.objects.filter(user=user).exists())
This avoids mocking altogether and gives a more accurate representation of your logic.
Solution 4:
unittest.PropertyMock
can be used to mock descriptors in a way that doesn't require mocking internal implementation details:
def test_valid(mocker, user_factory):
user = user_factory.build()
user.id = 1
data = {
'email': 'foo@example.com'
}
factory = APIRequestFactory()
request = factory.post('/', data=data)
force_authenticate(request, user)
mocker.patch.object(user, "save")
with mocker.patch('app.views.User.auth_token_set', new_callable=PropertyMock) as mock_auth_token_set:
mock_delete = mocker.MagicMock()
mock_auth_token_set.return_value.all.return_value.delete = mock_delete
response = ChangeEmail.as_view()(request)
assert response.status_code == status.HTTP_200_OK
assert mock_delete.call_count == 1
Post a Comment for "Mocking A RelatedManager In Django 2"