Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a Django test, how should I save a database object and then retrieve it from the database?

Tags:

python

django

I am using Django 1.8. I wrote the following code to test that a pre_save hook works correctly, but this code seems very inelegant. Is this the "proper way" to write this type of unit test?

class PreSaveTests(TestCase):
    def test_pre_save_hook(self):
        person = Person(name="Joe")
        person.save()
        person2 = Person.objects.get(pk = person.pk)
        # Confirm that the pre_save hook ran.
        # The hook sets person.is_cool to True.
        self.assertEqual(person2.is_cool, True)

This works fine, but it seems ugly.

The really ugly part is that person and person2 are the same database object. The only difference is that person2 was retrieved from the database.

like image 258
SerMetAla Avatar asked Dec 09 '22 02:12

SerMetAla


2 Answers

What you're doing in your test is perfectly fine. You can however simplify / improve it a little in my opinion.

I think you should use factories (you can use FactoryBoy). This way you won't have to update your test when you add/remove mandatory fields on your model. Also, you can remove irrelevant information from your test. In this case, the fact that the person name is Joe is completely irrelevant.

You can replace:

person = Person(name="Joe")
person.save()

with:

person = PersonFactory.create()

As Daniel mentioned, you don't need to reload the Person instance. So you don't have to do this:

person2 = Person.objects.get(pk = person.pk)

Finally, a small tip, you can use assertTrue instead of assertEquals(something, True):

class PreSaveTests(TestCase):

    def test_pre_save_hook(self):
        person = PersonFactory.create()
        self.assertTrue(person.is_cool)
like image 73
François Constant Avatar answered Dec 10 '22 15:12

François Constant


Firstly, I'm not sure why you think that's ugly: seems a perfectly reasonable way to test this functionality.

However, you could definitely make it simpler. Although Django instances don't have identity - that is, two instances retrieved from the database separately won't share modifications until they are saved and retrieved - when the pre-save hook runs, it modifies the existing instance. So in fact person will get the modification to set is_cool, so there is no need to retrieve and check person2.

like image 26
Daniel Roseman Avatar answered Dec 10 '22 14:12

Daniel Roseman