I try to setup my Django tests, and I noticed that when I run all tests TestRunner uses correct test database (for all aliases):
docker-compose exec my_project python manage.py test --keepdb
from django import db
from django.test.runner import DiscoverRunner
from apps.settings.models import Settings
class KeepDBTestRunner(DiscoverRunner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.verbosity = 2
self.keepdb = True
self.db_base_name = 'test_postgresdevuser'
def run_checks(self):
super().run_checks()
print(db.connections.databases)
----------------------------------------------
result
----------------------------------------------
{'default': {'NAME': 'test_postgresdevuser', 'USER': 'user', 'PASSWORD': '*******', 'HOST': 'postgres', 'PORT': 5432, 'ENGINE': 'apps.core.db_backends.open', 'TEST': {'SERIALIZE': False, 'DEPENDENCIES': [], 'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None},
'vk_master': {'NAME': 'test_postgresdevuser', 'USER': 'user', 'PASSWORD': '*******', 'HOST': 'postgres', 'PORT': 5432, 'ENGINE': 'apps.core.db_backends.open', 'TEST': {'SERIALIZE': False, 'DEPENDENCIES': [], 'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None},
But when I run tests for specific module, it uses the original database:
docker-compose exec my_project python manage.py test --keepdb apps.my_module
print(db.connections.databases)
----------------------------------------------
result
----------------------------------------------
{'default': {'NAME': 'postgresdevuser', 'USER': 'user', 'PASSWORD': '*******', 'HOST': 'postgres', 'PORT': 5432, 'ENGINE': 'apps.core.db_backends.open', 'TEST': {'SERIALIZE': False, 'DEPENDENCIES': [], 'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None},
'vk_master': {'NAME': 'postgresdevuser', 'USER': 'user', 'PASSWORD': '********', 'HOST': 'postgres', 'PORT': 5432, 'ENGINE': 'apps.core.db_backends.open', 'TEST': {'SERIALIZE': False, 'DEPENDENCIES': [], 'CHARSET': None, 'COLLATION': None, 'NAME': None, 'MIRROR': None}, 'ATOMIC_REQUESTS': False, 'AUTOCOMMIT': True, 'CONN_MAX_AGE': 0, 'OPTIONS': {}, 'TIME_ZONE': None},
What is the reason of such behavior? Using the original database is not allowed when I run tests on pre-production stages!
Project configuration:
Django=3.0.7
*.env* file:
DATABASE_URL=postgres://user:********@postgres:5432/postgresdevuser
*settings.py* file:
DATABASES = {
'default': env.db('DATABASE_URL', default=''),
'vk_master': env.db('DATABASE_URL', default=''),
}
DATABASES['vk_master']['ENGINE'] = 'apps.core.db_backends.open'
DATABASES['default']['ENGINE'] = 'apps.core.db_backends.open'
for db_name in DATABASES:
DATABASES[db_name]['TEST'] = {
'SERIALIZE': False,
'DEPENDENCIES': [],
}
I would be grateful for any advice!
Advertisement
Answer
I think it is a kind of bug in Django test. When there is no ‘databases’ parameter in any TestCase, it does not use the test database, but uses the original one. To overpass this, I redefined setup_databases method in my TestRunner like this:
class KeepDBTestRunner(DiscoverRunner):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.keepdb = True
def setup_databases(self, **kwargs):
# define aliases here. In original class aliases will be 'None' (from calling
# self.get_databases(suite)) and it causes a problem.
aliases = {'default', 'replica'}
return super().setup_databases(aliases=aliases)