views:

29

answers:

1

In the unit tests that I wrote, I provide a test fixture for each TestCase. However, I keep getting duplicate (IntegrityError) when it runs in the test suite.

So, I am wondering, isn't the database supposed to be created and populated at the beginning of each TestCase and after each test has be executed in that TestCase so that I can provide a different fixture for each TestCase?


Edit: added test code

class DashboardTestCase(TestCase):
    fixtures = ['initial.json']

    def setUp(self):
        u = User(username='su')
        u.save()
        self.name = "Test Dashboard"
        self.slug = "test-dashboard"
        self.description = "Test Description"
        self.fiscal_year = "2011"
        self.region = "Test Region"
        self.review_date = "2010-08-01"
        self.date_completed = "2009-03-15"
        self.prepared_by = "Test User"
        self.dashboard = Dashboard(name=self.name, description=self.description, fiscal_year=self.fiscal_year,
                                    region=self.region, review_date=self.review_date, date_completed=self.date_completed,
                                    prepared_by=self.prepared_by)
        self.dashboard.save()

    def testDashboardName(self):
        self.assertEqual(self.dashboard.name, self.name)
    def testDashboardDescription(self):
        self.assertEqual(self.dashboard.description, self.description)
    def testDashboardFiscalYear(self):
        self.assertEqual(self.dashboard.fiscal_year, self.fiscal_year)
    def testDashboardRegion(self):
        self.assertEqual(self.dashboard.region, self.region)
    def testDashboardReviewDate(self):
        self.assertEqual(self.dashboard.review_date, self.review_date)
    def testDashboardDateCompleted(self):
        self.assertEqual(self.dashboard.date_completed, self.date_completed)
    def testDashboardPreparedBy(self):
        self.assertEqual(self.dashboard.prepared_by, self.prepared_by)
    def testDashboardSlug(self):
        self.assertEqual(self.dashboard.slug, self.slug)
    def testDashboardSlugClash(self):
        # Create another dashboard with exactly the same name.
        self.dashboard2 = Dashboard(name='Test Dashboard')
        self.dashboard2.save()
        self.assertEqual(self.dashboard2.slug, 'test-dashboard1')

And the traceback:

Installing json fixture 'initial_data' from '/Users/Eric/Documents/DjangoProjects/MMR/../MMR/dashboard/fixtures'.
Problem installing fixture '/Users/Eric/Documents/DjangoProjects/MMR/../MMR/dashboard/fixtures/initial_data.json': Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/management/commands/loaddata.py", line 169, in handle
    obj.save(using=using)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/core/serializers/base.py", line 165, in save
    models.Model.save_base(self.object, using=using, raw=True)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/base.py", line 501, in save_base
    rows = manager.using(using).filter(pk=pk_val)._update(values)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/query.py", line 491, in _update
    return query.get_compiler(self.db).execute_sql(None)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 861, in execute_sql
    cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/models/sql/compiler.py", line 727, in execute_sql
    cursor.execute(sql, params)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django/db/backends/mysql/base.py", line 86, in execute
    return self.cursor.execute(query, args)
  File "build/bdist.macosx-10.5-i386/egg/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "build/bdist.macosx-10.5-i386/egg/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
IntegrityError: (1062, "Duplicate entry 'dashboard-action' for key 'app_label'")
+1  A: 

So, I am wondering, isn't the database supposed to be created and populated at the beginning of each TestCase

The database is only created once - at the beginning of the test run. That is, when you execute ./manage.py test. Test fixtures are loaded and removed respectively before and after executing each test method. This means that all of your fixtures are loaded to the database before each test method is executed. The database is dropped after all tests have been run.

I keep getting duplicate (IntegrityError) when it runs in the test suite

Without seeing the code the first place I would check would be initial_data if it exists. Initial_data is loaded to the database at the end of syncdb and this happens before testing starts. Make sure that your initial_data does not load any conflicting data.

Second place to look would be other fixtures, especially if you are using more than one fixture file per test class.

Update

Problem installing fixture '/Users/Eric/Documents/DjangoProjects/MMR/../MMR/dashboard/fixtures/initial_data.json':

It seems that the error occurs even before the fixture (initial.json) is loaded. There is most likely something inside initial_data.json that is duplicated and thereby violates database integrity.

This is how I'd go about troubleshooting:

"Duplicate entry 'dashboard-action' for key 'app_label'"
  1. Identify which model/table has a constraint that matches app_label
  2. Go through initial_data.json and find out if there exist two rows with the same value for app_label.
  3. Remove one of them and try again.

On a side note I would suggest renaming the test fixture to something else. It is easy to get confused between initial.json and initial_data.json. Unless you meant to use initial_data.json of course. In that case the fixtures = ... line is redundant and can be removed as initial_data.json will be loaded anyway.

Update 2

After smugly giving advice and patting myself on the back I came upon this Django bug. I am digging up more dirt on it. Will update again after I find more.

Manoj Govindan
Manoj, I've added the code above. Thanks! :)
Eric
@Eric: You are welcome :) Updated my answer. See above.
Manoj Govindan
@Eric: Can you remove `django.contrib.contenttypes` from your `INSTALLED_APPS` and try again? I just want to verify a theory.
Manoj Govindan
@Manoj, We just discovered a bug in one of our production applications. I am working to get that fixed and then will return to this. Thanks. :)
Eric