renderbox
renderbox

Reputation: 1655

Django SQLite trying to overwrite DB when testing

I am running into a strange issue with Django's test suite I am getting stuck on so I am looking for some insight as to how to fix it or at least where to look.

When I run the following to test my teddybears app:

python manage.py test teddybears

I get this error:

...django/db/backends/sqlite3/base.py", line 344, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: table "teddybears_teddybear" already exists

Shouldn't the DB be prefixed with the word "test" by default to avoid the name clashes? I renamed the DB to ":memory:" to try to avoid this but still the same error.

The development works fine and everything is functioning as expected, I just can't get the test suite to work. Any insight into what may be causing this or where to look would be greatly appreciated.

I am using SQLite for the local dev work and using Django 1.4.3

Here is the full stack trace:

> python manage.py test teadybears
Creating test database for alias 'default'...
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
    utility.execute()
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 49, in run_from_argv
    super(Command, self).run_from_argv(argv)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/test.py", line 72, in handle
    failures = test_runner.run_tests(test_labels)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/test/simple.py", line 381, in run_tests
    old_config = self.setup_databases()
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/test/simple.py", line 317, in setup_databases
    self.verbosity, autoclobber=not self.interactive)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/db/backends/creation.py", line 271, in create_test_db
    load_initial_data=False)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/__init__.py", line 150, in call_command
    return klass.execute(*args, **defaults)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
    return self.handle_noargs(**options)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 102, in handle_noargs
    cursor.execute(statement)
  File "/Work/projects/teadybears/venv/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 344, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.DatabaseError: table "teadybears_teadybear" already exists

REPLY:

Here are my DB settings:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'database.sqlite',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}

I did have this in there but it made no difference:

if 'test' in sys.argv:
    DATABASES['default']['NAME'] = ':memory:'

2 X Grrr....

It's unfortuneately not fixing the issue. I had tried everything suggested except change the DB name but that did not fix it either.

I did all the suggestions including:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'database.sqlite',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        'TEST_NAME': 'mud',
    }
}

It now asks me:

python manage.py test teddybears
Creating test database for alias 'default'...
Destroying old test database 'default'...
Type 'yes' if you would like to try deleting the test database 'mud', or 'no' to cancel:

Still produces the same error.

Would hate to move it to another clean project just to fix this but it's still getting annoying.


I have figured out what was tripping me up. One of the models on the project had a value set on the Meta Class that caused the testing to break.

class TeddybearExtra(Teddybear):

    class Meta:
        db_table = 'teddybears_teddybear'

As you can see it was a Subclass of the original model and since the "db_table" attribute was set explicitly it overrode the auto-generated table name. Lesson learned here is that setting the db_table attribute on the Meta object causes bad things to happen with test tools. Only do this if you absolutely need to handle it this way.

Upvotes: 1

Views: 2387

Answers (2)

Josh Smeaton
Josh Smeaton

Reputation: 48720

There are two sections in the documentation that might relate to the problem you're having:

https://docs.djangoproject.com/en/dev/topics/testing/overview/#the-test-database

By default the test databases get their names by prepending test_ to the value of the NAME settings for the databases defined in DATABASES. When using the SQLite database engine the tests will by default use an in-memory database (i.e., the database will be created in memory, bypassing the filesystem entirely!). If you want to use a different database name, specify TEST_NAME in the dictionary for any given database in DATABASES.

and..

If your tests rely on database access such as creating or querying models, be sure to create your test classes as subclasses of django.test.TestCase rather than unittest.TestCase.

In the example above, we instantiate some models but do not save them to the database. Using unittest.TestCase avoids the cost of running each test in a transaction and flushing the database, but for most applications the scope of tests you will be able to write this way will be fairly limited, so it’s easiest to use django.test.TestCase.

So first off, make sure your tests are subclassing from django.test.TestCase. Secondly, try setting TEST_NAME to testdb.sqlite and see if that solves your problem. You might also want to specify the path to the database as in /Work/database.sqlite, otherwise (I think) the database will be created in the directory you're executing your manage.py from, and that might not always be what you want.

Finally, make sure you're loading the correct settings file for your tests.

Upvotes: 4

pydanny
pydanny

Reputation: 8314

Are you pointing at the right settings module? Try:

python manage.py test teddybears --settings=myproject.settings.test

Upvotes: 2

Related Questions