Search code examples
djangodjango-modelsdjango-testingdjango-settingsdjango-2.2

Django unable to create tables for unit testing after upgrade from 1.8 to 2.2.4


After a successful upgrade from Django 1.8 to Django 2.2.4, when I run the tests it fails because Django does not create the database tables.

My test_settings.py file was working appropriately before the upgrade.

after debugging the Django db/backends it looks like the connection was created, but the tables were not. my suspicion is that test_setting.py is not configured well, although I copied everything from the setting.py file except the database configuration (that remained SQLite).

database configuration:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'test_database'
    }
}
INSTALLED_APPS = [
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'rest_framework.authtoken',
    'my_app',
    'mptt',
    'corsheaders',
    # audit app
    'easyaudit',
    'kronos',
    'django.contrib.admin',
]

The traceback that I'm getting (here it's, for example, the auth_user, but it reproduces for all the tables the same way):

Traceback (most recent call last):
  File "C:\Users\owner\Desktop\workspace\my_project\MyProject\services\tests\test_logging.py", line 33, in setUpClass
    cls.user = User.objects.get_or_create(username='logging_test_user', password='test_password')
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 538, in get_or_create
    return self.get(**kwargs), False
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 402, in get
    num = len(clone)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 256, in __len__
    self._fetch_all()
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\query.py", line 55, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\models\sql\compiler.py", line 1100, in execute_sql
    cursor.execute(sql, params)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "C:\Users\owner\Desktop\workspace\my_project\venv36\lib\site-packages\django\db\backends\sqlite3\base.py", line 383, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: auth_user

The tests getting executed with the environment variables of

DJANGO_SETTINGS_MODULE=MyProject.test_settings

Solution

  • It seems that there is a bug in django in this version (also since 2.2 maybe before, I didn't check more than that).

        databases = self.get_databases(suite)
        old_config = self.setup_databases(aliases=databases)
    

    databases variable in here wont be None in no case because in the get_databases function it calls to _get_databases() and incase it won't find any databases that got configured like it mention above, databases will set to set(), and that in setup_databases function there's a function called

    get_unique_databases_and_mirrors
    

    that check if there's is not database configured in the tests, and if not it will take the databases that configured in the settings file, but because its set to an empty set (set()) than it wont get into this condition, and therefore no database will get created.

    to pass that bug, you can create a class that will inherit unittests.Testcase, and configure the database like this:

    import django
    import unittest
    from django.conf import settings
    
    
    class MyTestCase(unittest.TestCase):
        databases = settings.DATABASES
    
        @classmethod
        def setUpClass(cls) -> None:
            super(MyTestCase, cls).setUpClass()
            django.setup()