ChatGPT解决这个技术问题 Extra ChatGPT

在 Django 1.7 中运行单元测试时禁用迁移

Django 1.7 引入了 database migrations

在 Django 1.7 中运行单元测试时,它会强制迁移,这需要很长时间。所以我想跳过 django 迁移,并在最终状态下创建数据库。

我知道忽略迁移可能是一种不好的做法,因为这部分代码不会被测试。但事实并非如此:我正在 CI 测试服务器 (jenkins) 中运行完整的迁移。我只想跳过本地测试中的迁移,其中速度很重要。

一些上下文:

在 Django 1.6 之前,使用 South 时,我使用了 SOUTH_TESTS_MIGRATE 设置:

默认情况下,如果 South 的 syncdb 命令在非交互模式下运行,它也会应用迁移,其中包括在您运行测试时 - 每次运行测试时它都会运行每次迁移。如果您希望测试运行程序使用 syncdb 而不是 migrate - 例如,如果您的迁移花费的时间太长而无法应用 - 只需在 settings.py 中设置 SOUTH_TESTS_MIGRATE = False。

但是,syncdb 不再存在,现在它已迁移。

从 Django 1.8 我将使用 --keepdb 参数:

--keepdb 选项可用于在测试运行之间保留测试数据库。这具有跳过创建和销毁操作的优点,这大大减少了运行测试的时间,尤其是大型测试套件中的测试。如果测试数据库不存在,它将在第一次运行时创建,然后为每次后续运行保留。在运行测试套件之前,任何未应用的迁移也将应用于测试数据库。

所以这个问题仅限于 Django 1.7。

我认为在 UT 期间,您确实没有以测试它们的方式运行迁移,因为您一开始使用的 DB 是不存在的。测试迁移实际上只在迁移现有数据库时发生。这个 1.7 迁移业务是我在 Django 中遇到的第一个真正的麻烦,但它确实是一个很大的刺激。 South 至少得到了适合迁移的测试场景。
django-test-without-migrations 包对我来说非常方便,您可能希望将接受的答案更改为 stackoverflow.com/a/28993456/200224
如果可能的话,我更喜欢避免添加新的依赖项。

m
mlissner

查看由 Bernie Sumption 发布到 Django 开发人员邮件列表的 this workaround

如果 makemigrations 尚未运行,“migrate”命令会将应用程序视为未迁移,并直接从模型创建表,就像 syncdb 在 1.6 中所做的那样。我为单元测试定义了一个名为“settings_test.py”的新设置模块,它从主设置模块导入 * 并添加以下行: MIGRATION_MODULES = {"myapp": "myapp.migrations_not_used_in_tests"} 然后我运行这样的测试: DJANGO_SETTINGS_MODULE="myapp.settings_test" python manage.py test 这个傻瓜会认为应用程序未迁移,因此每次创建测试数据库时,它都会反映models.py的当前结构。

在 Django 1.9 中,这种情况是 is improved somewhat,您可以将值设置为 None

MIGRATION_MODULES = {“myapp”:无}


请注意,myapp.migrations_not_used_in_tests 模块不应存在。
除了@bmihelac 对模块不存在的评论外,模块字符串必须包含子字符串“迁移”,原因参见:github.com/django/django/blob/stable/1.7.x/django/db/migrations/…
在 settings_test.py 中动态构建 MIGRATION_MODULES 的函数要点:gist.github.com/nealtodd/2869341f38f5b1eeb86d
泰。因此,我能够将单元测试从 13 秒减少到 4 秒。此外,使用 sqlite 进行测试可以发现更多的速度增益。对我来说,使用 postgres 进行测试需要 5.5 秒,但 sqlite 需要 4 秒。
从@nealtodd's gist 的评论来看,这里有一个解决方案的链接,该解决方案避免了一些陷阱并且非常简单:gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
G
Guillaume Vincent

这是我的设置文件的结尾:

class DisableMigrations(object):

    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None


TESTS_IN_PROGRESS = False
if 'test' in sys.argv[1:] or 'jenkins' in sys.argv[1:]:
    logging.disable(logging.CRITICAL)
    PASSWORD_HASHERS = (
        'django.contrib.auth.hashers.MD5PasswordHasher',
    )
    DEBUG = False
    TEMPLATE_DEBUG = False
    TESTS_IN_PROGRESS = True
    MIGRATION_MODULES = DisableMigrations()

基于此snippet

我仅在测试运行时才禁用迁移


好的!我也会添加 __setitem__(self, *_) 方法,因为我们遇到了像 settings.MIGRATION_MODULES['chroniker'] = 'db_migrations' 这样设置自己的迁移的应用程序的问题
非常感谢你,这是我发现的唯一真正有效的东西。
当以并行模式运行测试时,这不再适用于 Django 1.9。使用正常的非并行测试,它继续正常工作,但切换到并行模式会导致找不到表的错误。
@LeeSemel 在并行模式下,您可能想使用 rlmv 的解决方案
@guillaumevincent 在并行模式下使用 django-test-without-migrations 时我遇到了同样的问题
r
rlmv

django-test-without-migrations--nomigrations 标志添加到 manage.py test。奇迹般有效。


C
Community

更新:没关系,此更改是 reverted 在 1.10 最终版发布之前。希望它会在未来的版本中回归。

请注意,从 Django 1.10 开始,这可以通过测试数据库设置来控制。

MIGRATE 默认值:True 如果设置为 False,Django 将不会使用迁移来创建测试数据库。


F
FavorMylikes

我只是想出如何在 django 1.10 之后禁用迁移,可能对某人有帮助。这是 git 的 link

class DisableMigrations(dict):
    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None

DATABASES = DisableMigrations()

MIGRATION_MODULES = DisableMigrations()

django 1.10 的迁移有两个部分,请看 load_diskrecorder

load_disk 部分用于应用程序的迁移模型,在 INSTALL_APPrecorder 部分用于数据库连接 对于 1.9 之前的版本,我们需要在运行测试时设置 MIGRATION_MODULES={'do.not.migrate':'notmigrations'} 现在我们需要将其设置为 None像 MIGRATION_MODULES={'do.not.migrate':None} 因此,如果我们不想为任何应用程序进行迁移,只需扩展一个 dict 并为 getitem 函数返回 None,并在 DATABASES 处执行相同的操作,这是您需要做的正确事情

PS: 对于命令,您需要在 test 之后指定 --setting=module.path.settings_test_snippet PPS 如果您使用的是 pycharm不要 设置Run/Debug configurations 中的 --settings 选项,只需在自定义设置中添加 settings_test_snippet.py 的路径。就好了!!

请享用


D
David Arcos

https://gist.github.com/apollovy/22826f493ad2d06d9a9a22464730ce0b

MIGRATION_MODULES = {
    app[app.rfind('.') + 1:]: 'my_app.migrations_not_used_in_tests'
    for app in INSTALLED_APPS
}

欢迎来到stackoverflow。请查看 tourhelp center。通常鼓励不仅提供单行答案,还要解释为什么(您认为)您的答案是正确的。
d
devsnd

对于 django 1.9 及更高版本,Guillaume Vincent 的答案不再起作用,所以这是一个新的解决方案:

在定义 INSTALLED_APPS 之后,我在我的设置文件中使用了这个片段

if os.environ.get('TESTS_WITHOUT_MIGRATIONS', False):
    MIGRATION_MODULES = {
        app.split('.')[-1]: None for app in INSTALLED_APPS
    }

它遍历所有已安装的应用程序并将每个应用程序标记为没有迁移模块。请参阅 django docs for more information

使用此代码段,您可以运行测试,设置环境变量 TESTS_WITHOUT_MIGRATIONS,例如:

TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test

如果有人想直接在您的命令行中执行此操作,您可以在启动测试之前键入:export TESTS_WITHOUT_MIGRATIONS=1
L
LMB

从 Django 3.1 及更高版本开始,正确的方法是使用数据库设置字典中的 MIGRATE 设置。另请参阅 documentation

#settings.py
DATABASES = {
    'TEST': {
        'NAME': 'Foo',
        'MIGRATE': False
    }
}