I have a customer manager for a Django model which overrides the create
method to also save some related objects:
class CustomManager(models.Manager):
def create(self, amount, user, description):
txn = self.get_query_set().create(user, description)
txn.budget_transactions.create(amount)
return txn
My question is: how do I mock the call to txn.budget_transactions.create
to raise an exception?
The budget_transactions
attribute of the txn
object is an instance of django.db.models.fields.related.RelatedManager
. Using mock.patch
to mock this class doesn't work as it is declared dynamically - it can't be imported directly.
Does anyone know how to do this?
The reason that you can't just set the RelatedManager to a mock object is because django has overridden the set method on the object. So while it appears that the mock is getting set correctly because there are no complaints, it's actually silently setting budget_transactions
back to the RelatedManager. So if you really need to return a mock then you'll need to override the get method that returns the RelatedManager and return a mocked object instead.
Should end up lookig somthing like:
@mock.patch('django.db.models.fields.related.ForeignRelatedObjectsDescriptor.__get__')
def test_campaign_cancel(self, mock_manager):
mock_manager.return_value = mock.MagicMock()
mock_manager.return_value.create = Exception('Boom!')
That being said there are many pitfalls to this approach since it will be overriding a core django method and now ALL RelatedManagers will return a mocked object. From what I have experienced so far it's probably easier to explore other options.
RelatedManager
is a descriptor and has to be mocked using unittest.PropertyMock
from unittest import patch, MagicMock, PropertyMock, TestCase
class CustomManagerTest(TestCase):
@patch('app.managers.Transaction.budget_transactions', new_callable=PropertyMock)
def test_custom_manager_create(self, mock_budget_transactions):
mock_create = MagicMock()
mock_budget_transaction.return_value.create = mock_create
self.assertEqual(mock_create.call_count, 1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With