Как запустить тестовую базу данных Django только в памяти?

Мои модульные тесты Django занимают много времени, поэтому я ищу способы ускорить это. Я рассматриваю возможность установки SSD, но я знаю, что это тоже имеет свои недостатки. Конечно, есть вещи, которые я мог бы сделать с моим кодом, но я ищу структурное исправление. Даже запуск одного теста происходит медленно, так как база данных необходимо перестраивать/перенаправлять на юг каждый раз. Так вот моя идея...

Поскольку я знаю, что тестовая база данных всегда будет довольно маленькой, почему я не могу просто настроить систему, чтобы всегда хранить всю тестовую базу данных в ОЗУ? Никогда не касайтесь диска вообще. Как настроить это в Django? Я бы предпочел использовать MySQL, так как это то, что я использую в производстве, но если SQLite 3 или что-то еще облегчает это, я бы пошел таким образом.

Имеет ли SQLite или MySQL возможность полностью работать в памяти? Должно быть возможно настроить RAM-диск, а затем настроить тестовую базу данных для хранения там своих данных, но я не уверен, как сообщить Django/MySQL использовать другой каталог данных для определенной базы данных, тем более, что он продолжает стираться и воссоздал каждый прогон. (Я нахожусь на Mac FWIW.)

Ответ 1

Если вы установите свой движок базы данных на 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

Ответ 2

Обычно я создаю отдельный файл настроек для тестов и использую его в тестовой команде, например.

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
    

    чтобы убедиться, что все тесты действительно проходят.

Ответ 3

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, это не сработает для вас.

Ответ 4

Я не могу ответить на ваш главный вопрос, но есть несколько вещей, которые вы можете сделать, чтобы ускорить процесс.

Во-первых, убедитесь, что ваша база данных 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, и база данных будет создана с простой синхронизацией, которая будет намного быстрее, чем выполнение всех исторических миграций.

Ответ 5

Вы можете выполнить двойную настройку:

  • использовать транзакционные таблицы: состояние исходных состояний будет установлено с помощью отката базы данных после каждой тестовой системы.
  • поместите данные базы данных данных в ramdisk: вы получите гораздо больше, чем создание базы данных, а также запуск теста будет быстрее.

Я использую оба трюка, и я очень доволен.

Как настроить его для 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

Остерегайтесь, это просто для тестирования, после перезагрузки ваша база данных из памяти потеряна!

Ответ 6

Другой подход: иметь другой экземпляр MySQL, работающий в tempfs, который использует RAM-диск. Инструкции в этом сообщении в блоге: Ускорение MySQL для тестирования в Django.

Преимущества:

  • Вы используете точно такую ​​же базу данных, что ваш производственный сервер использует
  • Не нужно изменять конфигурацию mysql по умолчанию.

Ответ 7

Расширение ответа 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 используется только через командную строку, поэтому нет необходимости загромождать настройки