Missing Table When Running Django Unittest with Sqlite3
Question: I'm trying to run a unittest with Django 1.3. Normally, I use MySQL as my
database backend, but since this is painfully slow to spinup for a single
unittest, I'm using Sqlite3.

So to switch to Sqlite3 just for my unittests, in my settings.py I have:

    
    
    import sys
    if 'test' in sys.argv:
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME':'/tmp/database.db',
                'USER'       : '',
                'PASSWORD' : '',
                'HOST'     : '',
            }
        }
    

When I run my unittest with `python manage.py test myapp.Test.test_myfunc`, I
get the error:

    
    
    DatabaseError: no such table: django_content_type
    

Googling shows there are a
[few](https://code.djangoproject.com/wiki/NewbieMistakes#DjangosaysUnabletoOpenDatabaseFilewhenusingSQLite3)
of
[possible](http://www.pantz.org/software/sqlite/unabletoopendbsqliteerror.html)
[reasons](http://stackoverflow.com/questions/6157152/no-such-table-error-when-
running-a-django-server-from-eclipse) for this
[error](http://stackoverflow.com/questions/4636970/sqlite3-operationalerror-
unable-to-open-database-file), none of which seem applicable to me. I'm not
running Apache, so I don't see how permissions would be an issue. The file
/tmp/database.db is being created, so /tmp is writable. The app
django.contrib.contenttypes is included in my INSTALLED_APPS.

What am I missing?

Edit: I ran into this problem again in Django 1.5, but none of the proposed
solutions work.


Answer: In Django 1.4, 1.5, 1.6, 1.7, or 1.8 it _should_ be sufficient to use:

    
    
    if 'test' in sys.argv:
        DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'
    

It should not be necessary to override `TEST_NAME`1, nor to call `syncdb` in
order to run tests. As @osa points out, the default with the SQLite engine is
to create the test database in memory (`TEST_NAME=':memory:'`). Calling
`syncdb` should not be necessary because Django's test framework will do this
automatically via a call to `syncdb` or `migrate` depending on the Django
version.2 You can observe this with `manage.py test -v [2|3]`.

Very loosely speaking Django sets up the test environment by:

  1. Loading the regular database `NAME` from your `settings.py`
  2. Discovering and **constructing** your test classes (`__init__()` is called)
  3. Setting the database `NAME` to the value of `TEST_NAME`
  4. Running the tests against the database `NAME`

Here's the rub: At step 2, `NAME` is still pointing at your **regular** (non-
test) database. If your tests contain class-level queries or queries in
`__init__()`, they will be run against the regular database which is likely
not what you are expecting. This is identified in [bug
#21143](https://code.djangoproject.com/ticket/21143).

Don't do:

    
    
    class BadFooTests(TestCase):
        Foo.objects.all().delete()     # <-- class level queries, and
    
        def __init__(self):
            f = Foo.objects.create()   # <-- queries in constructor
            f.save()                   #     will run against the production DB
    
        def test_foo(self):
            # assert stuff
    

since these will be run against the database specified in `NAME`. If `NAME` at
this stage points to a valid database (e.g. your production database), the
query will run, but may have unintended consequences. If you have overridden
`ENGINE` and/or `NAME` such that it does not point to a pre-existing database,
an exception will be thrown because the test database has yet to be created:

    
    
    django.db.utils.DatabaseError: no such table: yourapp_foo  # Django 1.4
    DatabaseError: no such table: yourapp_foo                  # Django 1.5
    OperationalError: no such table: yourapp_foo               # Django 1.6+
    

Instead do:

    
    
    class GoodFooTests(TestCase):
    
        def setUp(self):
            f = Foo.objects.create()   # <-- will run against the test DB
            f.save()                   #
    
        def test_foo(self):
            # assert stuff
    

So, if you are seeing errors, check to see that your tests do not include any
queries that might hit the database outside of your test class method
definitions.

* * *

[1] In Django >= 1.7, `DATABASES[alias]['TEST_NAME']` is
[deprecated](https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-
OLD_TEST_NAME) in favour of
[`DATABASES[alias]['TEST']['NAME']`](https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-
DATABASE-TEST)  
[2] See the `create_test_db()` method in `db/backends/creation.py`

