Search code examples
pythondjangounit-testingmockingdjango-unittest

Mocking django's database save


I'm trying mock out a save method call on a django models.Model. I'm using Mock as my mocking library.

I'm testing a function in the file house_factory.py , which is located at apps.deps.house_factory.

house_factory.py: from apps.market.models import House

def create_house(location, date, price):
    house = House(id=None, date, price)
    house.save()

    # calculate some stuff and further expand the house instance
    # for example house.tag.add("some-tag")

    # save after calculations
    house.save()

I'd like to mock out the House model.

class HouseModelMock(mock.Mock):
    def save(self):
        pass

Testing method, is part of a unittest.TestCase class

  @patch('apps.deps.house_factory.House', new_callable=HouseModelMock)
  def create_house_test(self, MockedHouse):

      """ Constants """
      DAYS_FROM_TODAY = 55
      DATE = datetime.date.today() + datetime.timedelta(days=DAYS_FROM_TODAY)
      PRICE = 250000

    # A location is also a django module , I'm using factory_boy here for building a 'mocked' location
      location = LocationFactory.build()

      create_house(DATE, PRICE)
      MockedHouse.assert_called_with(None, DATE, PRICE)   
      MockedHouse.save.assert_called_with()

If I run this test I'm getting a:

call__ return self.call(*arg, **kw) MemoryError

This is one of my first attempts to get serious with django and testing. So maybe I'm setting things up wrong, to mock out a database call.

Any help is appreciated,

Jonas.


Solution

  • "This is one of my first attempts to get serious with django and testing" ... you don't need to mock database saves as Django automatically creates a test DB to run your test suite against whenever you run python manage.py test. Then simply assert the values stored in your DB.

    Ideally mock is used to patch own tests (and logic), rather than the default Django ones.

    Tip: use an in memory db for unit tests, such as sqlite put the below in your settings.py file:

    if 'test' in sys.argv:
        DATABASES['default']['ENGINE'] = 'sqlite3'
    

    This will significantly speed up your test run.