I'm a software developer for several years but new to python. I'm writing a unit test (so no database connection present) that involves a model in Django that accesses another model referenced via a foreign key connection. I want to mock the method that accesses this connection and replace the result with a hard coded response, that is different for each instance though.
Here's a minimal example:
### tests/test_MyTestCase.py
from unittest import TestCase
from djangoapi.models import *
class MyTestCase(TestCase):
def setUp(self):
self.instance1 = MyModel()
self.instance2 = MyModel()
foreignKey1 = MySubModel()
foreignKey1.my_value = 1
# Mock that self.instance1.submodel_set.all() returns [foreignKey1]
foreignKey2 = MySubModel()
foreignKey2.my_value = 2
# Mock that self.instance2.submodel_set.all() returns [foreignKey2]
def testSomething(self):
self.assertEqual(self.instance1.get_max_value(), 1)
self.assertEqual(self.instance2.get_max_value(), 2)
### models.py
from django.db import models
class MyModel(models.Model):
def get_max_value(self):
value = 0
# the return value of self.submodel_set.all() is what I want to mock
for model in self.submodel_set.all():
value = max(value, model.my_value)
return value
class Submodel(models.Model):
my_model = models.ForeignKey(MyModel, null=True, on_delete=models.SET_NULL)
my_value = models.IntegerField()
I tried several combinations of the @patch decorator
, Mock()
and MagicMock()
but could not get it to work. Thank you in advance!
After some more research, I found out that the main problem was that the mocking can't happen in the setUp
method, but must be done in the test methods themselves. This means some code duplication, but at least it works now. For reference, here's the working example:
from unittest import TestCase
from unittest.mock import patch
from djangoapi.models import *
class MyTestCase(TestCase):
def setUp(self):
self.my_model = MyModel()
self.foreignKey1 = MySubModel()
self.foreignKey1.my_value = 1
self.foreignKey2 = MySubModel()
self.foreignKey2.my_value = 2
@patch('djangoapi.models.MyModel.submodel_set')
def testSomething(self, mock_submodel_set):
mock_submodel_set.all.return_value = [self.foreignKey1]
self.assertEqual(self.my_model.get_max_value(), 1)
mock_submodel_set.all.return_value = [self.foreignKey2]
self.assertEqual(self.my_model.get_max_value(), 2)