Search code examples
djangodjango-testingdjango-nose

Django TestCase with fixtures causes IntegrityError due to duplicate keys


I'm having trouble moving away from django_nose.FastFixtureTestCase to django.test.TestCase (or even the more conservative django.test.TransactionTestCase). I'm using Django 1.7.11 and I'm testing against Postgres 9.2.

I have a Testcase class that loads three fixtures files. The class contains two tests. If I run each test individually as a single run (manage test test_file:TestClass.test_name), they each work. If I run them together, (manage test test_file:TestClass), I get

IntegrityError: Problem installing fixture '<path>/data.json': Could not load <app>.<Model>(pk=1): duplicate key value violates unique constraint "<app_model_field>_49810fc21046d2e2_uniq"

To me it looks like the db isn't actually getting flushed or rolled back between tests since it only happens when I run the tests in a single run.

I've stepped through the Django code and it looks like they are getting flushed or rolled back -- depending on whether I'm trying TestCase or TransactionTestCase.

(I'm moving away from FastFixtureTestCase because of https://github.com/django-nose/django-nose/issues/220)

What else should I be looking at? This seems like it should be a simple matter and is right within what django.test.TestCase and Django.test.TransactionTestCase are designed for.

Edit:

The test class more or less looks like this:

class MyTest(django.test.TransactionTestCase):  # or django.test.TestCase                        

    fixtures = ['data1.json', 'data2.json', 'data3.json']                                                      

    def test1(self):    
        return # I simplified it to just this for now.                            

    def test2(self):
        return # I simplified it to just this for now.                                               

Update:

I've managed to reproduce this a couple of times with a single test, so I suspect something in the fixture loading code.


Solution

  • One of my basic assumptions was that my db was clean for every TestCase. Tracing into the django core code I found instances where an object (in one case django.contrib.auth.User) already existed.

    I temporarily overrode _fixture_setup() to assert the db was clean prior to loading fixtures. The assertion failed.

    I was able to narrow the problem down to code that was in a TestCase.setUpClass() instead of TestCase.setUp(), and so the object was leaking out of the test and conflicting with other TestCase fixtures.

    What I don't understand completely is I thought that the db was dropped and recreated between TestCases -- but perhaps that is not correct.

    Update: Recent version of Django includes setUpTestData() that should be used instead of setUpClass()