一段时间以来,我的单元测试时间比预期的要长。我试图调试它几次没有太大的成功,因为延迟是在我的测试开始运行之前。这影响了我做任何远程接近测试驱动开发的能力(也许我的期望太高),所以我想知道我是否可以一劳永逸地解决这个问题。
运行测试时,测试开始和实际开始之间有70到80秒的延迟。例如,如果我为一个小模块运行测试(使用time python manage.py test myapp
),我会得到
<... bunch of unimportant print messages I print from my settings>
Creating test database for alias 'default'...
......
----------------------------------------------------------------
Ran 6 tests in 2.161s
OK
Destroying test database for alias 'default'...
real 1m21.612s
user 1m17.170s
sys 0m1.400s
大约1m18的1m:21位于
之间Creating test database for alias 'default'...
和
.......
线。换句话说,测试需要不到3秒,但数据库初始化似乎需要1:18min
我有大约30个应用程序,大多数有1到3个数据库模型,因此这应该可以了解项目大小。我使用SQLite进行单元测试,并实现了一些建议的改进。我无法发布我的整个设置文件,但很高兴添加所需的任何信息。
我确实使用跑步者
from django.test.runner import DiscoverRunner
from django.conf import settings
class ExcludeAppsTestSuiteRunner(DiscoverRunner):
"""Override the default django 'test' command, exclude from testing
apps which we know will fail."""
def run_tests(self, test_labels, extra_tests=None, **kwargs):
if not test_labels:
# No appnames specified on the command line, so we run all
# tests, but remove those which we know are troublesome.
test_labels = (
'app1',
'app2',
....
)
print ('Testing: ' + str(test_labels))
return super(ExcludeAppsTestSuiteRunner, self).run_tests(
test_labels, extra_tests, **kwargs)
并在我的设置中:
TEST_RUNNER = 'config.test_runner.ExcludeAppsTestSuiteRunner'
我也尝试将django-nose
与django-nose-exclude
我已经阅读了很多关于如何自己加速测试的内容,但是没有找到关于如何优化或避免数据库初始化的任何线索。我已经看到了关于尝试不使用数据库进行测试的建议,但我不知道或者不知道如何完全避免这种情况。
如果
请告诉我同样,我不需要如何加速测试本身,但初始化(或开销)。我希望上面的例子花费10秒而不是80秒。
非常感谢
我使用--verbose 3
运行测试(针对单个应用)并发现这与迁移有关:
Rendering model states... DONE (40.500s)
Applying authentication.0001_initial... OK (0.005s)
Applying account.0001_initial... OK (0.022s)
Applying account.0002_email_max_length... OK (0.016s)
Applying contenttypes.0001_initial... OK (0.024s)
Applying contenttypes.0002_remove_content_type_name... OK (0.048s)
Applying s3video.0001_initial... OK (0.021s)
Applying s3picture.0001_initial... OK (0.052s)
... Many more like this
我压扁了所有的迁移但仍然很慢。
答案 0 :(得分:27)
解决我的问题的最终解决方案是强制Django在测试期间禁用迁移,这可以通过这样的设置来完成
TESTING = 'test' in sys.argv[1:]
if TESTING:
print('=========================')
print('In TEST Mode - Disableling Migrations')
print('=========================')
class DisableMigrations(object):
def __contains__(self, item):
return True
def __getitem__(self, item):
return "notmigrations"
MIGRATION_MODULES = DisableMigrations()
或使用https://pypi.python.org/pypi/django-test-without-migrations
我的整个测试现在需要大约1分钟,一个小应用程序需要5秒钟。
在我的情况下,我不需要迁移进行测试,因为我在迁移时更新了测试,并且不使用迁移来添加数据。这不适合所有人
答案 1 :(得分:20)
使用pytest
!
pip install pytest-django
pytest --nomigrations
代替./manage.py test
./manage.py test
花费2分钟11.86秒pytest --nomigrations
费用为2.18秒您可以在项目根目录中创建名为pytest.ini
的文件,并在那里指定default command line options和/或Django settings。
# content of pytest.ini
[pytest]
addopts = --nomigrations
DJANGO_SETTINGS_MODULE = yourproject.settings
现在您只需使用pytest
运行测试,并为您节省一些打字。
通过将--reuse-db
添加到默认命令行选项,您可以进一步加快后续测试。
[pytest]
addopts = --nomigrations --reuse-db
但是,只要更改了数据库模型,就必须运行pytest --create-db
一次到force re-creation of the test database。
如果您需要在测试期间启用gevent monkey patching,可以在项目根目录中创建一个名为pytest
的文件,其中包含以下内容,将执行位转换为它({{1并运行chmod +x pytest
进行测试,而不是./pytest
:
pytest
您可以创建一个#!/usr/bin/env python
# -*- coding: utf-8 -*-
# content of pytest
from gevent import monkey
monkey.patch_all()
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "yourproject.settings")
from django.db import connection
connection.allow_thread_sharing = True
import re
import sys
from pytest import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
文件来测试gevent monkey修补是否成功:
test_gevent.py
<强>参考强>
答案 2 :(得分:12)
在迁移文件中没有更改时使用./manage.py test --keepdb
答案 3 :(得分:3)
数据库初始化确实需要太长时间......
我有一个项目,大约有相同数量的模型/表(大约77个),大约350个测试,总共花费1分钟来运行所有内容。在分配了2个cpus和2GB内存的流浪汉机器中进行游戏。我还使用py.test和pytest-xdist插件来并行运行多个测试。
您可以做的另一件事是告诉django重用测试数据库,并且只在更改架构时重新创建它。您也可以使用SQLite,以便测试将使用内存数据库。这两种方法都解释如下 https://docs.djangoproject.com/en/dev/topics/testing/overview/#the-test-database
编辑:如果上述选项都不起作用,还有一个选项是让您的单元测试继承自django SimpleTestCase,或者使用不创建数据库的自定义测试运行器在这里的答案中解释:django unit tests without a db。
然后你可以使用像这样的库来模拟对数据库的django调用(我承认这是我写的):https://github.com/stphivos/django-mock-queries
通过这种方式,您可以快速在本地运行单元测试,并让CI服务器担心运行需要数据库的集成测试,然后再将代码合并到一个不是生产单元的稳定dev / master分支。 / p>