Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django object ids increment between unit tests

I'm using Django 1.2.3-3+squeeze1 on Debian squeeze with PostgreSQL 8.4.7-0squeeze2 (though I don't think PostgreSQL is relevant here), and running Django unit tests based on unittest with the following setUp and tearDown

   def setUp(self):
        print "running setup"
        self.c = Client()
        self.user = User.objects.create_user('faheem', '[email protected]', 'foo')
        self.logged_in = self.c.login(username='faheem', password='foo')
        settings.MEDIA_ROOT='/tmp/'
        #settings.ZIP_UPLOAD='/var/tmp/zip/'

    def tearDown(self):
        print "running teardown"
        FolderUpload.objects.all().delete()
        FileUpload.objects.all().delete()
        ZipFileUpload.objects.all().delete()
        OldFileUpload.objects.all().delete()
        # FIXME: Quick & dirty fix for the time being. Should make this a delete method.
        os.system("rm -rf "+ settings.ZIP_UPLOAD + "/*")

The idea is for everything to be removed from the database between running unit tests. According to the unittest documentation, that is what tearDown is for. The problem I am having is that there still seems to be some state saved between the different unit tests. Specifically, I'm seeing that the ids get incremented. So lets say if I create one ZipFileUpload object in test1, and then create one ZipFileUpload object in test2, then I would expect both ids to be 1, but what I see is that is id 1 for test1 and id 2 fortest2. This would make sense if the ids come from some index which lives outside these tables. I don't know enough about how Diango does this to know if that is in fact the case. If they are doing it this way, I have no idea why. Any clarification on this point would be appreciated.

Regardless, I would settle for a clean way to drop the database, if anyone can suggest one. This method should probably go into teadDown. Testing Django applications mentions the following function, but I failed to import it from django.test.utils. Confusingly, this function seems to be in django/db/backends/creation.py.

destroy_test_db(old_database_name, verbosity=1)

Destroys the database whose name is in stored in NAME in the DATABASES, and sets NAME to use the provided name.

The first part of this sentence is Ok - "Destroy the database whose name is stored in NAME in the DATABASES", but what is meant by "sets NAME to use the provided name" mean? I assume the provided name is old_database_name,

It is not clear what NAME is in the context. Is it the NAME in DATABASES, and if so, why do I need to set something that is already set? I assume the provided name is old_database_name, but if so, why would I want to set it to an argument called old_database_name? This sentence is unchanged in development docs.

EDIT:

After a reply from Steve Mayne (see below), I thought I would elaborate on the background of this a little bit.

This application was originally written over 2007/2008/2009, including the unit tests. During most of that time, I was using pre 1.0 releases of Django. According to Ken Cochran's Django Release History, 1.0 was released on September 3rd, 2008. The setup described worked fine during that time. I see that the tearDown function above was originally written in December 2007. So, perhaps Django's behavior changed?

In hindsight, I realise that emptying the tables, as tearDown does above, does not guarantee that the id count will be reset to 1, since the sequence can be a separate object from the table.

Thanks to Steve for his solution. If it exists, I'd like to hear about a portable solution to the sequence reset. I'd also be interested in an explanation of how to make the destroy_test_db function above work.

like image 984
Faheem Mitha Avatar asked Jun 06 '11 09:06

Faheem Mitha


Video Answer


1 Answers

You can reset the ID sequence on each table using the following SQL:

SELECT pg_catalog.setval(pg_get_serial_sequence('table_name', 'id'), 1);

You should only do this if your table is empty.

like image 186
Steve Mayne Avatar answered Sep 23 '22 15:09

Steve Mayne