简体   繁体   English

加速Django测试

[英]Speeding up Django Testing

Im looking to learn more about your testing flows with Django. 我希望通过Django了解有关您的测试流程的更多信息。

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

Im encountering difficulties when using test driven development. 我在使用测试驱动开发时遇到了困难。 The test runner of Django constantly creates all db models in a test db when starting. Django的测试运行器在启动时不断在测试数据库中创建所有数据库模型。 For our current projects (between 40 and 240 models) this means it takes easily 20s for tests to start. 对于我们当前的项目(40到240个型号),这意味着测试开始需要20秒。

This makes it completely unworkable for testing a new feature often. 这使得经常测试新功能完全不可行。 My question, how do you guys work around this? 我的问题,你们是如何解决这个问题的呢?

I've tried a few things in the past a.) - change the testloader to reuse the same test db every time and apply migrations when needed b.) - run my unit tests from within the __main__ flow of python files 我在过去尝试了一些事情。) - 更改testloader以每次重用相同的测试数据库并在需要时应用迁移b。) - 从python文件的__main__流程中运行我的单元测试

option b is awkward with the sys.path, option a is doable but doesnt seem to be the django way. 选项b对于sys.path很尴尬,选项a是可行的,但似乎不是django方式。

Update: Option A is indeed not such a bad solution. 更新:选项A确实不是一个糟糕的解决方案。 Its just quite a bit of effort. 它只是相当多的努力。 Which makes me believe people use a different workaround. 这让我相信人们使用不同的解决方法。 SQL lite could be that workaround. SQL lite可能就是那种解决方法。 But im guessing there are more. 但我猜还有更多。

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

change the testloader to reuse the same test db every time and apply migrations when needed 更改测试加载程序以每次重用相同的测试数据库,并在需要时应用迁移

  1. I don't see anything wrong in writing your own test runner that merely truncates the tables instead of dropping and creating the database. 在编写自己的测试运行器时,我没有看到任何错误,只是截断表而不是删除和创建数据库。 This is djangoic in that it solves a specific problem. 这是djangoic,因为它解决了一个特定的问题。 There is a ticket open for allowing grouping of test cases into test suites. 有一个打开的票据允许将测试用例分组到测试套件中。 Once it is fixed you should be able to group your test cases into suites for easier management. 修复后,您应该能够将测试用例分组到套件中以便于管理。 You can also inspect the patch attached to the ticket and see if it will suit your purpose. 您还可以检查附加到故障单的补丁,看它是否适合您的目的。

  2. As Ned suggested you can use an in memory database. 正如Ned 建议您可以使用内存数据库。 This depends to a large extent on your data model and queries being portable across databases. 这在很大程度上取决于您的数据模型和可跨数据库移植的查询。

  3. If you haven't already try to reorganize your test cases. 如果您尚未尝试重新组织测试用例。 In my experience not all test classes need to sub class django.test.TestCase . 根据我的经验,并非所有测试类都需要子类django.test.TestCase Find out those test classes that can do with sub classing unittest.TestCase . 找出那些可以用sub classing unittest.TestCase做的测试类。 This will speed up things a little bit. 这将加快东西一点点

  4. Reorganize fixtures. 重组固定装置。 Move common fixtures to a single file and load it before the test run rather than inside each test class (using fixtures = [...] ). 将常用灯具移动到单个文件并在测试运行之前加载它,而不是在每个测试类中加载(使用fixtures = [...] )。

I don't like the idea of using a different database (SQLite) for testing, so my unit tests use the same database as the production application - postgres. 我不喜欢使用不同的数据库(SQLite)进行测试,因此我的单元测试使用与生产应用程序相同的数据库 - postgres。

Out of the box, this makes creating/destroying the database the slowest step in running tests. 开箱即用,这使得创建/销毁数据库成为运行测试的最慢步骤。

Django 1.8 will solve this problem with the --keepdb flag Django 1.8将使用--keepdb标志解决这个问题

But we're still not there yet, so we must make do with other means. 但是我们还没有,所以我们必须用其他方法。

Solution 1) Use pytest-django 解决方案1)使用pytest-django

You can use that to make your tests run without re-creating the database. 您可以使用它来运行测试而无需重新创建数据库。 It works. 有用。 If you only care about running tests on the command line, I suggest this. 如果您只关心在命令行上运行测试,我建议这样做。

In my case, I like to use the PyCharm IDE, and being able to run tests by right clicking files/methods is definitely a plus for me, so I had to go with... 在我的情况下,我喜欢使用PyCharm IDE,并且能够通过右键单击文件/方法来运行测试对我来说绝对是一个加分,所以我不得不去...

Solution 2) The TEST_MIRROR trick. 解决方案2)TEST_MIRROR技巧。

In your settings.py file, configure your database like: 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',
        }
    }

So, "mydb" is the database that will be used for normal execution and "mydbtesting" is for tests. 因此,“mydb”是用于正常执行的数据库,“mydbtesting”用于测试。

The TEST_MIRROR setting is not actually meant for this, but the fact is that if you run tests with a database configured like that, Django will not re-create/destroy which is what we want. TEST_MIRROR设置实际上并不适用于此,但事实是如果您使用这样配置的数据库运行测试,Django将不会重新创建/销毁我们想要的内容。

But first we have to create that database with something like: 但首先我们必须使用以下内容创建该数据库:

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

Then whenever you want to run tests fast, just set the USE_TEST_DB environment variable to '1'. 然后,只要您想快速运行测试,只需将USE_TEST_DB环境变量设置为“1”即可。 To get same benefit on Pycharm, you can go to Run/Debug Configurations, Defaults / Django tests, then on Environment variables, add USE_TEST_DB = 1 要在Pycharm上获得相同的好处,您可以转到运行/调试配置,默认值/ Django测试,然后在环境变量上添加USE_TEST_DB = 1


UPDATE: 更新:

Sample application is on Github: https://github.com/freedomsponsors/www.freedomsponsors.org/blob/099ec1a7a1c404eba287d4c93d58c8cf600b2769 示例应用程序在Github上: https//github.com/freedomsponsors/www.freedomsponsors.org/blob/099ec1a7a1c404eba287d4c93d58c8cf600b2769

I have found another way to speed up the testing. 我找到了另一种加速测试的方法。 If your test models are auth users ( User model), and you set a password for them, the hashing function takes a decent number of milliseconds to finish. 如果您的测试模型是auth用户( User模型),并且您为它们设置了密码,则散列函数需要相当多的毫秒才能完成。 What I do is add this to my test settings: 我所做的是将其添加到我的测试设置:

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

This enforces MD5 hashing for password which is much faster than the default one. 这会对密码强制执行MD5哈希,这比默认密码要快得多。 In my case, this improved 12 tests, each creates 7 users, from 4.5 seconds to 500 ms. 在我的例子中,这改进了12个测试,每个测试创建7个用户,从4.5秒到500毫秒。

Be careful not to add this to your production settings! 小心不要将其添加到您的生产设置中!

You can run only tests that interest you specyfically, look here: http://docs.djangoproject.com/en/dev/topics/testing/?from=olddocs#running-tests 您只能运行您特别感兴趣的测试,请查看此处: http ://docs.djangoproject.com/en/dev/topics/testing/?from = olddocs #running-tests

Like in this example - run just specyfic TestCase: 就像在这个例子中 - 运行specyfic TestCase:

$ ./manage.py test animals.AnimalTest

As for the test database - it is created and destroyed each time the test runs :( Also for testing you could use sqlite database if it is possible in your workflow. 至于测试数据库 - 每次测试运行时都会创建和销毁它:(对于测试,如果可以在工作流程中使用,则可以使用sqlite数据库。

I have found another way to speed up testing. 我找到了另一种加速测试的方法。 The most time consuming operation is writing to/reading from hard drive (I'm using sqlite for testing). 最耗时的操作是写入/读取硬盘驱动器(我使用sqlite进行测试)。 The solution is to create ramdisk , and put the sqlite database file there. 解决方案是创建ramdisk ,并将sqlite数据库文件放在那里。 I have reduced testing time by factor of 10. 我将测试时间减少了10倍。

Creating ramdisk: 创建ramdisk:

#!/bin/sh

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

Changing db file path: 更改数据库文件路径:

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

As of Django 1.8, you can keep the test database around so that you don't rebuild it every time you test. 从Django 1.8开始,您可以保留测试数据库,以便每次测试时都不会重建它。 Just add the --keepdb flag. 只需添加--keepdb标志即可。

python manage.py test --keepdb

When you have new migrations, exclude the --keepdb flag and the test database will be built from scratch. 进行新迁移时,请排除--keepdb标志,并且将从头开始构建测试数据库。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM