Ускорение тестирования Django

Мне нужно больше узнать о ваших тестовых потоках в Django.

Справочная информация http://docs.djangoproject.com/en/dev/topics/testing/

Я сталкиваюсь с трудностями при использовании разработки, основанной на тестах. Тест-драйв Django постоянно создает все db-модели в тестовом db при запуске. Для наших текущих проектов (от 40 до 240 моделей) это означает, что для запуска тестов требуется 20 секунд.

Это делает его совершенно неработоспособным для частого тестирования новой функции. Мой вопрос, как вы, парни, работаете вокруг этого?

Я пробовал несколько вещей в прошлом a.) - измените тестовый загрузчик для повторного использования одного и того же теста db каждый раз и при необходимости примените миграцию b.) - запустите мои модульные тесты из потока __main__ файлов python

опция b неудобна с sys.path, опция a выполнима, но, похоже, не является способом django.

Обновление: Вариант А действительно не является таким плохим решением. Это просто немало усилий. Это заставляет меня полагать, что люди используют другое обходное решение. SQL Lite может быть обходным путем. Но я думаю, что их больше.

Ответ 1

изменить тестовый загрузчик для повторного использования одного и того же теста db каждый раз и применять миграции при необходимости

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

  • Как показано в Ned , вы можете использовать базу данных в памяти. Это во многом зависит от модели данных и запросов, которые переносятся через базы данных.

  • Если вы еще не пытались реорганизовать свои тестовые примеры. По моему опыту не всем тестовым классам нужен подкласс django.test.TestCase. Выясните те тестовые классы, которые могут выполнять подкласс unittest.TestCase. Это немного ускорит работу.

  • Реорганизовать светильники. Переместите общие светильники в один файл и загрузите их перед тестовым запуском, а не внутри каждого тестового класса (используя fixtures = [...]).

Ответ 2

Использование базы данных SQLite в памяти во время тестирования определенно ускоряет работу.

Ответ 3

Мне не нравится идея использования другой базы данных (SQLite) для тестирования, поэтому мои модульные тесты используют ту же базу данных, что и производственное приложение - postgres.

Из коробки это делает создание/уничтожение базы данных самым медленным шагом при выполнении тестов.

Django 1.8 решит эту проблему с флагом - keepdb

Но мы все еще не находимся, поэтому мы должны делать это с другими средствами.

Решение 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, вы можете перейти к параметрам Run/Debug Configurations, Defaults/Django, затем к переменным среды, добавить USE_TEST_DB = 1


UPDATE:

Пример приложения находится на Github: https://github.com/freedomsponsors/www.freedomsponsors.org/blob/099ec1a7a1c404eba287d4c93d58c8cf600b2769

Ответ 4

Вы можете запускать только те тесты, которые вам интересны, посмотрите здесь: http://docs.djangoproject.com/en/dev/topics/testing/?from=olddocs#running-tests

Как в этом примере - запустите только specyfic TestCase:

$ ./manage.py test animals.AnimalTest

Что касается тестовой базы данных - она ​​создается и уничтожается при каждом запуске теста:( Кроме того, для тестирования вы можете использовать базу данных sqlite, если это возможно в вашем рабочем процессе.

Ответ 5

Я нашел еще один способ ускорить тестирование. Если ваши тестовые модели являются авторизованными пользователями (модель User), и вы устанавливаете для них пароль, хеширующая функция занимает достойное количество миллисекунд. Что я делаю, добавьте это в мои тестовые настройки:

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

Это обеспечивает хеширование MD5 для пароля, которое намного быстрее, чем значение по умолчанию. В моем случае это улучшенные 12 тестов, каждый из которых создает 7 пользователей, от 4,5 секунд до 500 мс.

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

Ответ 6

Я нашел другой способ ускорить тестирование. Самая трудоемкая операция - запись/чтение с жесткого диска (я использую sqlite для тестирования). Решение состоит в том, чтобы создать ramdisk и поместить там файл базы данных sqlite. Я сократил время тестирования в 10 раз.

Создание ramdisk:

#!/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',
    }
}

Ответ 7

Как и в Django 1.8, вы можете хранить тестовую базу данных так, чтобы вы не перестраивали ее каждый раз, когда вы тестируете. Просто добавьте флаг -keepdb.

python manage.py test --keepdb

Когда у вас есть новые миграции, исключите флаг -keepdb, и тестовая база данных будет построена с нуля.

Ответ 8

Вот простые тестовые инструменты, которые не поддерживают перезагрузку базы данных вместе с сигналами, поэтому вам не нужно заботиться о тестовой базе данных https://github.com/plus500s/django-test-tools