【问题标题】:Disable migrations when running unit tests in Django 1.7在 Django 1.7 中运行单元测试时禁用迁移
【发布时间】:2014-09-29 10:47:55
【问题描述】:

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 已经不存在了,现在是 migrate

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

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

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

【问题讨论】:

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

标签: django unit-testing django-migrations


【解决方案1】:

查看this workaround,由 Bernie Sumption 发布到 Django 开发者邮件列表:

如果 makemigrations 尚未运行,“migrate”命令将处理 一个未迁移的应用程序,并直接从模型创建表 就像 1.6 中的 syncdb 一样。我为单元定义了一个新的设置模块 名为“settings_test.py”的测试,它从主目录导入 * 设置模块并添加这一行:

MIGRATION_MODULES = {"myapp": "myapp.migrations_not_used_in_tests"}

然后我运行这样的测试:

DJANGO_SETTINGS_MODULE="myapp.settings_test" python manage.py 测试

这些傻瓜会认为应用程序未迁移,因此 每次创建测试数据库时,它都会反映当前 models.py的结构。

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

MIGRATION_MODULES = {"myapp": 无}

【讨论】:

【解决方案2】:

我的设置文件到此结束:

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 时遇到了同样的问题
【解决方案3】:

django-test-without-migrations--nomigrations 标志添加到manage.py test。像魅力一样工作。

【讨论】:

    【解决方案4】:

    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。通常鼓励不仅提供单行答案,而且还要解释为什么(您认为)您的答案是正确的。
    【解决方案5】:

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


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

    迁移

    默认:True

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

    【讨论】:

      【解决方案6】:

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

      我在我的设置文件中使用这个sn-p,在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

      使用这个 sn-p 你可以运行你的测试,设置环境变量TESTS_WITHOUT_MIGRATIONS,例如:

      TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test
      

      【讨论】:

        【解决方案7】:

        我只是想知道如何在 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_APP 以及recorder 用于数据库连接的部分 对于 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 的路径。没关系!!

        享受

        【讨论】:

          猜你喜欢
          • 2015-02-02
          • 2011-08-13
          • 2015-01-02
          • 2014-12-13
          • 2017-03-13
          • 2014-05-28
          • 2013-02-01
          • 2021-10-11
          • 2011-07-12
          相关资源
          最近更新 更多