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)