Мои модульные тесты Django занимают много времени, поэтому я ищу способы ускорить это. Я рассматриваю возможность установки SSD, но я знаю, что это тоже имеет свои недостатки. Конечно, есть вещи, которые я мог бы сделать с моим кодом, но я ищу структурное исправление. Даже запуск одного теста происходит медленно, так как база данных необходимо перестраивать/перенаправлять на юг каждый раз. Так вот моя идея...
Поскольку я знаю, что тестовая база данных всегда будет довольно маленькой, почему я не могу просто настроить систему, чтобы всегда хранить всю тестовую базу данных в ОЗУ? Никогда не касайтесь диска вообще. Как настроить это в Django? Я бы предпочел использовать MySQL, так как это то, что я использую в производстве, но если SQLite 3 или что-то еще облегчает это, я бы пошел таким образом.
Имеет ли SQLite или MySQL возможность полностью работать в памяти? Должно быть возможно настроить RAM-диск, а затем настроить тестовую базу данных для хранения там своих данных, но я не уверен, как сообщить Django/MySQL использовать другой каталог данных для определенной базы данных, тем более, что он продолжает стираться и воссоздал каждый прогон. (Я нахожусь на Mac FWIW.)
Если вы установите свой движок базы данных на sqlite3 при выполнении своих тестов, Django будет использовать базу данных в памяти.
Я использую такой код в моем settings.py
, чтобы настроить движок на sqlite при выполнении моих тестов:
if 'test' in sys.argv:
DATABASE_ENGINE = 'sqlite3'
Или в Django 1.2:
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'sqlite3'}
И, наконец, в Django 1.3 и 1.4:
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
(Полный путь к серверу не обязательно необходим Django 1.3, но делает настройку переадресации совместимой.)
Вы также можете добавить следующую строку, если у вас возникли проблемы с южными переходами:
SOUTH_TESTS_MIGRATE = False
Обычно я создаю отдельный файл настроек для тестов и использую его в тестовой команде, например.
python manage.py test --settings=mysite.test_settings myapp
Он имеет два преимущества:
Вам не нужно проверять test
или любое такое волшебное слово в sys.argv, test_settings.py
может просто быть
from settings import *
# make tests faster
SOUTH_TESTS_MIGRATE = False
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
Или вы можете дополнительно настроить его для своих нужд, чисто отделяя тестовые настройки от производственных настроек.
Еще одно преимущество заключается в том, что вы можете запускать тест с помощью ядра базы данных вместо sqlite3, избегая тонких ошибок, поэтому при разработке используйте
python manage.py test --settings=mysite.test_settings myapp
и перед выполнением кода запускается один раз
python manage.py test myapp
чтобы убедиться, что все тесты действительно проходят.
MySQL поддерживает механизм хранения под названием "MEMORY", который вы можете настроить в своей конфигурации базы данных (settings.py
) следующим образом:
'USER': 'root', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'OPTIONS': {
"init_command": "SET storage_engine=MEMORY",
}
Обратите внимание, что механизм хранения MEMORY не поддерживает столбцы blob/text, поэтому, если вы используете django.db.models.TextField
, это не сработает для вас.
Я не могу ответить на ваш главный вопрос, но есть несколько вещей, которые вы можете сделать, чтобы ускорить процесс.
Во-первых, убедитесь, что ваша база данных MySQL настроена на использование InnoDB. Затем он может использовать транзакции для отката состояния db перед каждым тестом, что по моему опыту привело к значительному ускорению. Вы можете передать команду инициализации базы данных в файле settings.py(синтаксис Django 1.2):
DATABASES = {
'default': {
'ENGINE':'django.db.backends.mysql',
'HOST':'localhost',
'NAME':'mydb',
'USER':'whoever',
'PASSWORD':'whatever',
'OPTIONS':{"init_command": "SET storage_engine=INNODB" }
}
}
Во-вторых, вам не нужно каждый раз запускать южные миграции. Установите SOUTH_TESTS_MIGRATE = False
в свои settings.py, и база данных будет создана с простой синхронизацией, которая будет намного быстрее, чем выполнение всех исторических миграций.
369 tests in 498.704s
до 369 tests in 41.334s
. Это более чем в 10 раз быстрее!
Вы можете выполнить двойную настройку:
Я использую оба трюка, и я очень доволен.
Как настроить его для MySQL на Ubuntu:
$ sudo service mysql stop
$ sudo cp -pRL /var/lib/mysql /dev/shm/mysql
$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ sudo service mysql start
Остерегайтесь, это просто для тестирования, после перезагрузки ваша база данных из памяти потеряна!
Другой подход: иметь другой экземпляр MySQL, работающий в tempfs, который использует RAM-диск. Инструкции в этом сообщении в блоге: Ускорение MySQL для тестирования в Django.
Преимущества:
Расширение ответа Anurag. Я упростил процесс, создав те же самые параметры test_settings и добавив следующее к manage.py
if len(sys.argv) > 1 and sys.argv[1] == "test":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.test_settings")
else:
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
кажется более чистым, поскольку sys уже импортирован и manage.py используется только через командную строку, поэтому нет необходимости загромождать настройки