Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking Django Model and save()

I have the following scenario:

in my models.py

class FooBar(models.Model):
    description = models.CharField(max_length=20)

in my utils.py file.

from models import FooBar

def save_foobar(value):
    '''acts like a helper method that does a bunch of stuff, but creates a 
    FooBar object and saves it'''

    f = FooBar(description=value)
    f.save()

in tests.py

from utils import save_foobar

@patch('utils.FooBar')
def test_save_foobar(self, mock_foobar_class):

    save_mock = Mock(return_value=None)
    mock_foobar_class.save = save_mock

    save_foobar('some value')

    #make sure class was created
    self.assertEqual(mock_foobar_class.call_count, 1) #this passes!!!

    #now make sure save was called once
    self.assertEqual(save_mock.call_count, 1) #this fails with 0 != 1 !!!

This is a simplified version of what I'm trying to do... so please don't get hungup on why I have a utils file and a helper function for this (in real life it does several things). Also, please note, while simplified, this is an actual working example of my problem. The first call to test call_count returns 1 and passes. However, the second one returns 0. So, it would seem like my patch is working and getting called.

How can I test that not only an instance of FooBar gets created, but also that the save method on it gets called?

like image 937
David S Avatar asked May 11 '12 03:05

David S


People also ask

What is Save () in Django?

The save method is an inherited method from models. Model which is executed to save an instance into a particular Model. Whenever one tries to create an instance of a model either from admin interface or django shell, save() function is run.

How do I save changes in Django model?

To save data in Django, you normally use . save() on a model instance. However the ORM also provides a . update() method on queryset objects.

What is mocking in Django?

When mocking in a test, we are in a certain way making fun of our software or of the function we are testing, simulating the behaviour of a specific external functionality. In Python there is a package in the standard library that helps us apply mocks during our tests.


1 Answers

Here is your problem, you currently have:

mock_foobar_class.save = save_mock

since mock_foobar_class is a mocked class object, and the save method is called on an instance of that class (not the class itself), you need to assert that save is called on the return value of the class (aka the instance).

Try this:

mock_foobar_class.return_value.save = save_mock

I hope that helps!

like image 84
Matthew J Morrison Avatar answered Sep 28 '22 01:09

Matthew J Morrison