如何在Django中跳过创建一个测试数据库

3
我们的 Django 应用程序中使用了两个数据库,一个是"事务性"数据库,另一个是"分析性"数据库(用作数据仓库)。"事务性"数据库是使用 Django 模型创建的,而"分析性"数据库则是使用我们自定义的脚本创建的,其中包含多个"事务性"表的原始 SQL 连接。
当我们运行 Django 应用程序的测试时,这两个数据库都会创建其对应的测试版本,比如说,"test_transactional" 和 "test_analytical"。"test_transactional" 的创建是正常的,但我们希望跳过"test_analytical"的创建,因为该数据库将由我们的自定义脚本创建并填充。
以下是来自 Jenkins 日志的代码片段:
python manage.py test --keepdb cis.tests.test_views --  
noinput --settings=strainprint.settings.local --verbosity=2
...
Using existing test database for alias 'analytics' 
('test_strainprint_analytics')...
...
Synchronizing apps without migrations:
Creating tables...
Creating table django_admin_log
Creating table auth_permission
...

有没有一种方法可以在Django中实现这个?我们使用的是django 1.10版本。
2个回答

4
如您所请求的,这就是我最终实现的内容。"遗留"数据库是指我们希望跳过创建的数据库——Django应该假定它已经存在。
首先,您需要添加这个稍作修改的测试运行程序:project/runner.py
from django.test.runner import DiscoverRunner
from django.test.utils import get_unique_databases_and_mirrors
from django.db import connections


class LegacyDatabaseRunner(DiscoverRunner):
    """
    Test runner that will skip attempting to create any database with LEGACY=True
    in its TEST configuration dictionary
    """
    def setup_databases(self, **kwargs):
        return _setup_databases(
            self.verbosity, self.interactive, self.keepdb, self.debug_sql,
            self.parallel, **kwargs
        )


def _setup_databases(verbosity, interactive, keepdb=False, debug_sql=False, parallel=0, **kwargs):
    """Clone of django.test.utils.setup_databases"""
    test_databases, mirrored_aliases = get_unique_databases_and_mirrors()

    old_names = []

    for db_name, aliases in test_databases.values():
        first_alias = None
        for alias in aliases:
            connection = connections[alias]

            # This clause is all that's been added. If the database's TEST configuration
            # has LEGACY=True, skip attempting to create the database, and don't add it
            # to the list of databases to tear down after testing is complete.
            if connection.settings_dict.get('TEST', {}).get('LEGACY', False):
                continue

            old_names.append((connection, db_name, first_alias is None))

            # Actually create the database for the first connection
            if first_alias is None:
                first_alias = alias
                connection.creation.create_test_db(
                    verbosity=verbosity,
                    autoclobber=not interactive,
                    keepdb=keepdb,
                    serialize=connection.settings_dict.get('TEST', {}).get('SERIALIZE', True),
                )
                if parallel > 1:
                    for index in range(parallel):
                        connection.creation.clone_test_db(
                            suffix=str(index + 1),
                            verbosity=verbosity,
                            keepdb=keepdb,
                        )
            # Configure all other connections as mirrors of the first one
            else:
                connections[alias].creation.set_as_test_mirror(connections[first_alias].settings_dict)

    # Configure the test mirrors.
    for alias, mirror_alias in mirrored_aliases.items():
        connections[alias].creation.set_as_test_mirror(
            connections[mirror_alias].settings_dict)

    if debug_sql:
        for alias in connections:
            connections[alias].force_debug_cursor = True

    return old_names

接下来,将其设置为您的项目/settings.py中的默认运行程序:
TEST_RUNNER = 'project.runner.LegacyDatabaseRunner'

如果你想跳过某些数据库的创建,请在设置中使用LEGACY=True标记:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': ...,
        },
        'legacy_db1': {
            'ENGINE': 'sql_server.pyodbc',
            'NAME': ...,
            'TEST': {
                'LEGACY': True,  # Do not manage this database during tests
            },
        },
    }

希望您能正常运行manage.py test
请注意,该方法无法在并行测试时使用。我对ParallelTestSuite.init_worker进行了一些修改,并对setup_databases进行了微调,但它还没有完全功能。
旧答案,临时可行:
这不是特别安全的方法,因为此配置选项的语义可能会更改,但您可以声明一个数据库是另一个数据库的“副本”。
DATABASES = {
    'default': {
        'NAME': 'transactional',
         ...
    },
    'analytical': {
        'NAME': 'analytical',
        ...
        'TEST': {
            'MIRROR': 'default',
        },
    }
}

MIRROR 配置选项的文档可在此处找到:https://docs.djangoproject.com/en/dev/topics/testing/advanced/#testing-primary-replica-configurations

相关的 Django 源代码在这里:https://github.com/django/django/blob/master/django/test/utils.py


我完全忘记了这个问题,因为我学会了接受 5 分钟的测试设置。所以出于某种原因,现在我尝试使用它,但问题出在这部分(来自文档): 当测试环境被配置时,副本的测试版本不会被创建。相反,对副本的连接将被重定向到默认指向的位置。 这是一个问题,因为我的查询应该进入分析数据库,但会被重定向到事务处理数据库,而后者没有分析表。 - Luka
最终我不得不创建一个自定义的测试运行器。它允许我在Django设置中标记数据库为“legacy”,并且在测试设置期间,运行器将简单地跳过任何被标记的数据库。如果有用的话,我可以在某个地方分享实现。 - HorsePunchKid
是的,那会很有帮助。也许你可以编辑你的回答? - Luka
1
如果底层数据库不同(MySQL、postgres),则 MIRROR 选项无法工作。 - famagusta
这个答案应该被标记为最佳答案! - kaahxd

1

我没有找到忽略第一个数据库创建的解决方案,但是如果所有迁移都已在现有数据库上创建,则可以重复使用现有数据库。

通常,我使用以下设置使用pytest执行我的Django测试: enter image description here

请注意最后一个字段:附加参数

它的值为:--exitfirst --reuse-db。使用这个附加参数的pytest也可以在命令行上工作,但我更喜欢PyCham因为它有调试器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接