【问题标题】:Speeding up Django Testing加速 Django 测试
【发布时间】:2010-09-26 17:51:01
【问题描述】:

我希望详细了解您使用 Django 进行的测试流程。

背景资料 http://docs.djangoproject.com/en/dev/topics/testing/

我在使用测试驱动开发时遇到了困难。 Django 的测试运行器在启动时不断地在一个测试数据库中创建所有数据库模型。 对于我们当前的项目(40 到 240 个模型),这意味着开始测试需要 20 秒。

这使得经常测试新功能完全不可行。 我的问题,你们如何解决这个问题?

我过去曾尝试过一些事情 a.) - 更改测试加载器以每次重用相同的测试数据库并在需要时应用迁移 b.) - 在__main__ python 文件流中运行我的单元测试

选项 b 使用 sys.path 很尴尬,选项 a 是可行的,但似乎不是 django 的方式。

更新: 选项 A 确实不是一个糟糕的解决方案。它只是相当多的努力。这让我相信人们使用不同的解决方法。 SQL lite 可能就是这种解决方法。但我猜还有更多。

【问题讨论】:

  • 除了我在下方评论中的明智建议之外,您还可以利用时间学习椅子剑术:xkcd.com/303

标签: python django unit-testing


【解决方案1】:

我找到了另一种加快测试速度的方法。如果您的测试模型是身份验证用户(User 模型),并且您为他们设置了密码,则散列函数需要相当多的毫秒才能完成。我所做的就是将此添加到我的测试设置中:

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.MD5PasswordHasher',
)

这对密码强制执行 MD5 哈希,这比默认密码快得多。 就我而言,这改进了 12 个测试,每个测试创建 7 个用户,从 4.5 秒到 500 毫秒。

注意不要将此添加到您的生产设置中!

【讨论】:

    【解决方案2】:

    更改测试加载器以每次重用相同的测试数据库并在需要时应用迁移

    1. 我认为编写自己的测试运行程序没有任何问题,它只是截断表而不是删除和创建数据库。这是 djangoic,因为它解决了一个特定的问题。有一个ticket 开放用于允许将测试用例分组到测试套件中。一旦它被修复,您应该能够将您的测试用例分组到套件中以便于管理。您还可以检查附在票证上的补丁,看看它是否适合您的目的。

    2. 作为 Ned suggested,您可以使用内存数据库。这在很大程度上取决于您的数据模型和跨数据库可移植的查询。

    3. 如果您还没有尝试重新组织测试用例。根据我的经验,并非所有测试类都需要子类django.test.TestCase。找出那些可以使用子类unittest.TestCase 的测试类。这将加快速度一点

    4. 重新组织装置。将常用夹具移动到单个文件并在测试运行之前加载它,而不是在每个测试类中加载(使用fixtures = [...])。

    【讨论】:

      【解决方案3】:

      在测试期间使用内存中的 SQLite 数据库肯定会加快速度。

      【讨论】:

      • 这被证明是一个真正的助推器:D
      【解决方案4】:

      我不喜欢使用不同的数据库 (SQLite) 进行测试的想法,因此我的单元测试使用与生产应用程序相同的数据库 - postgres。

      开箱即用,这使得创建/销毁数据库成为运行测试中最慢的步骤。

      Django 1.8 将使用--keepdb flag 解决这个问题

      但我们还没有到达那里,所以我们必须通过其他方式凑合。

      解决方案 1) 使用pytest-django

      您可以使用它来运行您的测试,而无需重新创建数据库。有用。 如果你只关心在命令行上运行测试,我建议这样做。

      就我而言,我喜欢使用 PyCharm IDE,并且能够通过右键单击文件/方法来运行测试对我来说绝对是一个加分项,所以我不得不...

      解决方案 2) TEST_MIRROR 技巧。

      在您的 settings.py 文件中,配置您的数据库,如下所示:

      if os.getenv('USE_TEST_DB') == '1':
          DATABASES = {
              'default': {
                  'ENGINE': 'django.db.backends.postgresql_psycopg2',
                  'NAME': 'mydbtesting',
                  'USER': 'mydb',
                  'PASSWORD': 'mydb',
                  'HOST': 'localhost',
                  'PORT': '5432',
                  'TEST_MIRROR': 'default',
              }
          }
      else:
          DATABASES = {
              'default': {
                  'ENGINE': 'django.db.backends.postgresql_psycopg2',
                  'NAME': 'mydb',
                  'USER': 'mydb',
                  'PASSWORD': 'mydb',
                  'HOST': 'localhost',
                  'PORT': '5432',
              }
          }
      

      因此,“mydb”是用于正常执行的数据库,“mydbtesting”用于测试。

      TEST_MIRROR 设置实际上并不是为了这个,但事实是,如果您使用这样配置的数据库运行测试,Django 将不会重新创建/销毁我们想要的。

      但首先我们必须使用以下内容创建该数据库:

      export USE_TEST_DB=1
      ./manage.py syncdb --migrate
      

      然后,只要您想快速运行测试,只需将USE_TEST_DB 环境变量设置为“1”。 要在 Pycharm 上获得同样的好处,您可以转到运行/调试配置、默认值/Django 测试,然后在环境变量上,添加 USE_TEST_DB = 1


      更新:

      示例应用在 Github 上:https://github.com/freedomsponsors/www.freedomsponsors.org/blob/099ec1a7a1c404eba287d4c93d58c8cf600b2769

      【讨论】:

        【解决方案5】:

        从 Django 1.8 开始,您可以保留测试数据库,这样您就不会在每次测试时都重新构建它。只需添加 --keepdb 标志。

        python manage.py test --keepdb
        

        当您有新的迁移时,排除 --keepdb 标志,测试数据库将从头开始构建。

        【讨论】:

          【解决方案6】:

          您只能运行您特别感兴趣的测试,请看这里:http://docs.djangoproject.com/en/dev/topics/testing/?from=olddocs#running-tests

          就像在这个例子中一样 - 只运行特定的 TestCase:

          $ ./manage.py test animals.AnimalTest
          

          至于测试数据库 - 每次测试运行时都会创建和销毁它:( 如果在您的工作流程中可能,您也可以使用 sqlite 数据库进行测试。

          【讨论】:

          • 将这种方法与 Makefiles 一起使用也很有用,因此您可以对要测试的套件的不同部分使用不同的 make 命令:例如 make test all、make test core、make test imageproc 等
          【解决方案7】:

          我找到了另一种加快测试速度的方法。最耗时的操作是写入/读取硬盘驱动器(我使用sqlite 进行测试)。解决方案是创建ramdisk,并将sqlite数据库文件放在那里。我将测试时间缩短了 10 倍。

          创建虚拟磁盘:

          #!/bin/sh
          
          mkdir -p /tmp/ramdisk; chmod 777 /tmp/ramdisk
          mount -t tmpfs -o size=256M tmpfs /tmp/ramdisk/
          

          更改 db 文件路径:

          DATABASES = {
              'default': {
                  'ENGINE': 'django.db.backends.sqlite3',
                  'NAME': '/tmp/ramdisk/test.db',
                  'TEST_NAME': '/tmp/ramdisk/test.db',
              }
          }
          

          【讨论】:

            【解决方案8】:

            这里是简单的测试工具,提供无需重新加载的数据库以及信号,因此您无需关心测试数据库https://github.com/plus500s/django-test-tools

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-06-09
              • 1970-01-01
              • 1970-01-01
              • 2014-08-26
              • 1970-01-01
              • 2014-02-21
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多