Django - Mocking the save method on a model
--
Track title: CC B Schuberts Piano Sonata No 16 D
--
Chapters
00:00 Question
01:41 Accepted answer (Score 13)
02:29 Thank you
--
Full question
https://stackoverflow.com/questions/2766...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#python #django #unittesting #mocking
#avk47
ACCEPTED ANSWER
Score 13
After some more googling, I found something that works :
@mock.patch.object(models.KangaUser, 'save')
@mock.patch('django.contrib.auth.models.User')
def test_create(self, user_class_mock, kangauser_save_mock):
# Mocking configuration
# User
user_class_mock.objects = mock.MagicMock()
user_class_mock.objects.create_user = mock.MagicMock()
user_class_mock.objects.create_user.return_value = User(id=1)
# Test
kangauser_manager = models.KangaUserManager()
kanga_user = kangauser_manager.create(self.username, self.email, self.password, self.last_name, self.first_name, self.request, self.registered, self.send_confirmation)
# Checks
# create_user called with good parameters
user_class_mock.objects.create_user.assert_called_with(username=self.username, email=self.email, password=self.password, first_name=self.first_name, last_name=self.last_name)
# KangaUser
self.assertTrue(kangauser_save_mock.called)
So, the trick was to use @mock.patch.object !
ANSWER 2
Score 0
With pytest-mock you can do:
def test_create(self, mocker):
mocker.patch("path_to_the_kanga_user_manager.KangaUser.save")
ANSWER 3
Score 0
@CBrunain's answer got me started on the right path, particularly with mock.patch.object(models.KangaUser, 'save'). In my case, however, my unit test still needed Model.save to function how it's supposed to.
I ended up finding the wraps parameter:
wraps: Item for the mock object to wrap. If wraps is not None then calling the Mock will pass the call through to the wrapped object (returning the real result). Attribute access on the mock will return a Mock object that wraps the corresponding attribute of the wrapped object (so attempting to access an attribute that doesn’t exist will raise an AttributeError).
In other words, you can mock save without overriding its functionality just for the purpose of checking how many times it's been called:
@mock.patch.object(models.KangaUser, 'save', wraps=models.KangaUser.save)
To give the full answer, the code below is the same as @CBrunain's but with the adjusted mock and an additional Mock.call_count example:
@mock.patch.object(models.KangaUser, 'save', wraps=models.KangaUser.save)
@mock.patch('django.contrib.auth.models.User')
def test_create(self, user_class_mock, kangauser_save_mock):
# Mocking configuration
# User
user_class_mock.objects = mock.MagicMock()
user_class_mock.objects.create_user = mock.MagicMock()
user_class_mock.objects.create_user.return_value = User(id=1)
# Test
kangauser_manager = models.KangaUserManager()
kanga_user = kangauser_manager.create(self.username, self.email, self.password, self.last_name, self.first_name, self.request, self.registered, self.send_confirmation)
# Checks
# create_user called with good parameters
user_class_mock.objects.create_user.assert_called_with(username=self.username, email=self.email, password=self.password, first_name=self.first_name, last_name=self.last_name)
# KangaUser
self.assertTrue(kangauser_save_mock.called)
self.assertEqual(1, kangauser_save_mock.call_count)