Spec-Zone.ru › Django 2.1

Написание и выполнение тестов

См. также

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

Этот документ разделен на два основных раздела. Сначала мы объясним, как писать тесты с Django. Затем, мы объясним, как их запускать.

Написание тестов

Единые тесты Django используют модуль стандартной библиотеки Python: unittest. Этот модуль определяет тесты с использованием подхода на основе классов.

Вот пример, который наследуется от django.test.TestCase, который является подклассом unittest.TestCase, который выполняет каждый тест внутри транзакции для обеспечения изоляции:

from django.test import TestCase
from myapp.models import Animal

class AnimalTestCase(TestCase):
    def setUp(self):
        Animal.objects.create(name="lion", sound="roar")
        Animal.objects.create(name="cat", sound="meow")

    def test_animals_can_speak(self):
        """Animals that can speak are correctly identified"""
        lion = Animal.objects.get(name="lion")
        cat = Animal.objects.get(name="cat")
        self.assertEqual(lion.speak(), 'The lion says "roar"')
        self.assertEqual(cat.speak(), 'The cat says "meow"')

Когда вы выполняете свои тесты, стандартное поведение утилиты для тестирования — это поиск всех тестовых случаев (то есть подклассов unittest.TestCase) в любом файле, имя которого начинается с test, автоматически создает набор тестов из этих тестовых случаев и выполняет этот набор.

Для получения более подробной информации о unittest, см. документацию Python.

Где должны храниться тесты?

Шаблон по умолчанию startapp создает файл tests.py в новой приложении. Это может быть хорошо, если у вас всего несколько тестов, но по мере роста набора тестов, вам, вероятно, захочется перестроить его в пакет тестов, чтобы вы могли разделить свои тесты на разные подмодули, такие как test_models.py, test_views.py, test_forms.py, и т.д. Не стесняйтесь выбирать любую организационную схему, которая вам нравится.

См. также Использование исполнителя тестов Django для тестирования повторно используемых приложений.

Предупреждение

Если ваши тесты полагаются на доступ к базе данных, такой как создание или запросы моделей, обязательно создавайте свои тестовые классы как подклассы django.test.TestCase, а не unittest.TestCase.

Использование unittest.TestCase позволяет избежать затрат на выполнение каждого теста в транзакции и сброс базы данных, но если ваши тесты взаимодействуют с базой данных, их поведение будет отличаться в зависимости от порядка, в котором их выполняет тестовый запуск. Это может привести к тому, что тесты пройдут при выполнении изолированно, но потерпят неудачу при выполнении в наборе.

Выполнение тестов

После написания тестов запустите их, используя команду test утилиты вашего проекта manage.py:

$ ./manage.py test

Обнаружение тестов основано на встроенном обнаружении тестов модуля unittest. По умолчанию это обнаружит тесты в любом файле с именем «test*.py» в текущем рабочем каталоге.

Вы можете указать конкретные тесты для запуска, передавая любое количество «тег-меток» в ./manage.py test. Каждая тег-метка может быть полным Python-путем к пакету, модулю, TestCase подклассу или тестовому методу. Например:

# Run all the tests in the animals.tests module
$ ./manage.py test animals.tests

# Run all the tests found within the 'animals' package
$ ./manage.py test animals

# Run just one test case
$ ./manage.py test animals.tests.AnimalTestCase

# Run just one test method
$ ./manage.py test animals.tests.AnimalTestCase.test_animals_can_speak

Вы также можете указать путь к каталогу для обнаружения тестов в нем:

$ ./manage.py test animals/

Вы можете указать пользовательский шаблон имени файла с помощью параметра -p (или --pattern) если ваши тестовые файлы имеют другое имя, чем шаблон test*.py.

$ ./manage.py test --pattern="tests_*.py"

Если нажать Ctrl-C во время выполнения тестов, тестовый запуск будет ждать завершения текущего теста и затем выйдет корректно. Во время корректного завершения тестовый запуск выведет детали любых сбоев тестов, сообщит о том, сколько тестов было выполнено, и сколько ошибок и сбоев было обнаружено, и уничтожит любые тестовые базы данных, как обычно. Таким образом, нажатие Ctrl-C может быть очень полезным, если вы забыли передать опцию --failfast, заметили, что некоторые тесты неожиданно терпят неудачу, и хотите получить подробности о сбоях, не дожидаясь завершения всего запуска тестов.

Если вы не хотите ждать завершения текущего теста, вы можете нажать Ctrl-C второй раз, и запуск тестов остановится немедленно, но не корректно. Подробности о выполненных тестах до прерывания не будут сообщены, а любые тестовые базы данных, созданные запуском, не будут уничтожены.

Тестирование с включенными предупреждениями

Хорошей идеей является запуск тестов с включенными предупреждениями Python: python -Wa manage.py test. Флаг -Wa сообщает Python о том, чтобы отображать предупреждения о устаревании. Django, как и многие другие библиотеки Python, использует эти предупреждения, чтобы указывать, когда функции исчезают. Также он может отмечать области в вашем коде, которые не строго неверны, но могут быть улучшены.

Тестовая база данных

Тесты, которые требуют базы данных (именно, тесты моделей), не будут использовать вашу «реальную» (производственную) базу данных. Для тестов создаются отдельные, пустые базы данных.

Независимо от того, пройдут тесты или нет, тестовые базы данных уничтожаются после выполнения всех тестов.

Вы можете предотвратить уничтожение тестовых баз данных с помощью параметра test --keepdb. Это сохранит тестовую базу данных между запусками. Если база данных не существует, она будет сначала создана. Также будут применены все миграции, чтобы она оставалась актуальной.

Имена тестовых баз данных по умолчанию создаются путем добавления префикса test_ к значению каждого NAME в DATABASES. При использовании SQLite тесты по умолчанию будут использовать базу данных в памяти (т. е. база данных будет создана в памяти, полностью минуя файловую систему!). Словарь TEST в DATABASES предлагает ряд настроек для настройки вашей тестовой базы данных. Например, если вы хотите использовать другое имя базы данных, укажите NAME в словаре TEST для любой данной базы данных в DATABASES.

В PostgreSQL, USER также потребуется доступ для чтения к встроенной postgres базе данных.

Помимо использования отдельной базы данных, тестовый запуск будет использовать все те же настройки базы данных, что и в файле настроек: ENGINE, USER, HOST и т. д. Тестовая база данных создается пользователем, указанным в USER, поэтому вам нужно убедиться, что данная учетная запись пользователя имеет достаточные привилегии для создания новой базы данных в системе.

Для точного управления кодировкой символов вашей тестовой базы данных используйте параметр CHARSET TEST. Если вы используете MySQL, вы также можете использовать параметр COLLATION для управления конкретным набором сортировки, используемым тестовой базой данных. См. документацию по настройкам для получения подробной информации об этих и других расширенных настройках.

Если используется SQLite в памяти с SQLite, кеш общего доступа активирован, поэтому вы можете писать тесты с возможностью совместного использования базы данных между потоками.

Получение данных из вашей производственной базы данных при запуске тестов?

Если ваш код пытается получить доступ к базе данных при компиляции модулей, это произойдет *до* настройки тестовой базы данных, что может привести к неожиданным результатам. Например, если у вас есть запрос к базе данных в коде уровня модуля и существует реальная база данных, данные из производства могут загрязняться ваши тесты. *В любом случае, не стоит иметь подобные запросы к базе данных на стадии импорта в вашем коде* - перепишите ваш код так, чтобы это не происходило.

Это также относится к настраиваемым реализациям ready().

См. также

Раздел дополнительных тем по тестированию многочисленных баз данных.

Порядок выполнения тестов

Для обеспечения того, что весь TestCase код начинается с чистой базы данных, исполняющий тесты Django переупорядочивает тесты следующим образом:

  • Все TestCase подклассы выполняются в первую очередь.
  • Затем все остальные тесты Django (тесты, основанные на SimpleTestCase, включая TransactionTestCase) выполняются без гарантии или принудительного порядка среди них.
  • Затем выполняются любые другие тесты unittest.TestCase (включая doctests), которые могут изменять базу данных без восстановления её в исходное состояние.

Примечание

Новый порядок тестов может раскрыть неожиданные зависимости от порядка выполнения тестов. Это касается doctests, которые зависели от состояния базы данных, оставленного заданным тестом TransactionTestCase; их необходимо обновить, чтобы они могли выполняться независимо.

Вы можете изменить порядок выполнения внутри групп, используя опцию test --reverse. Это может помочь убедиться, что ваши тесты независимы друг от друга.

Эмуляция отката

Любые начальные данные, загруженные в миграции, будут доступны только в тестах TestCase и не в тестах TransactionTestCase, а также только на бэкендах, поддерживающих транзакции (самым важным исключением является MyISAM). Это также верно для тестов, которые полагаются на TransactionTestCase, такие как LiveServerTestCase и StaticLiveServerTestCase.

Django может перезагружать эти данные для вас на основе каждого теста, установив опцию serialized_rollback в значение True в теле TestCase или TransactionTestCase, но обратите внимание, что это замедлит этот набор тестов примерно в 3 раза.

Приложения сторонних разработчиков или разработчики, работающие с MyISAM, должны будут установить это значение; однако, в целом, вы должны разрабатывать свои собственные проекты с использованием транзакционной базы данных и использовать TestCase для большинства тестов, и поэтому вам не понадобится эта настройка.

Первоначальная сериализация обычно очень быстрая, но если вы хотите исключить некоторые приложения из этого процесса (и немного ускорить выполнение тестов), вы можете добавить эти приложения в TEST_NON_SERIALIZED_APPS.

Чтобы предотвратить повторную загрузку сериализованных данных, установка serialized_rollback=True отключает сигнал post_migrate при сбросе тестовой базы данных.

Другие условия тестов

Независимо от значения настройки DEBUG в вашем файле конфигурации, все тесты Django выполняются с DEBUG=False. Это гарантирует, что наблюдаемый вывод вашего кода соответствует тому, что будет видно в рабочей среде.

Кэши не очищаются после каждого теста, и выполнение «manage.py test fooapp» может внести данные из тестов в кэш рабочей системы, если вы запускаете тесты в рабочей среде, потому что, в отличие от баз данных, отдельный «тестовый кэш» не используется. Это поведение может измениться в будущем.

Понимание вывода тестов

При запуске тестов вы увидите ряд сообщений, поскольку тестовый запуск готовится. Уровень детализации этих сообщений можно контролировать с помощью опции verbosity в командной строке:

Creating test database...
Creating table myapp_animal
Creating table myapp_mineral

Это говорит о том, что тестовый запуск создает тестовую базу данных, как описано в предыдущем разделе.

После создания тестовой базы данных Django выполнит ваши тесты. Если всё пройдёт успешно, вы увидите что-то вроде этого:

----------------------------------------------------------------------
Ran 22 tests in 0.221s

OK

Однако, если возникнут ошибки тестов, вы увидите подробные сведения о том, какие тесты не прошли:

======================================================================
FAIL: test_was_published_recently_with_future_poll (polls.tests.PollMethodTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/dev/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_poll
    self.assertIs(future_poll.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (failures=1)

Полное объяснение этого вывода ошибки выходит за рамки данного документа, но оно довольно интуитивно. Вы можете обратиться к документации библиотеки Python unittest для получения подробностей.

Обратите внимание, что код возврата скрипта тестового запуска равен 1 при любом количестве неудачных и ошибочных тестов. Если все тесты пройдены, код возврата равен 0. Эта функция полезна, если вы используете скрипт тестового запуска в скрипте оболочки и вам нужно проверить успех или неудачу на этом уровне.

Ускорение тестов

Выполнение тестов параллельно

Пока ваши тесты должным образом изолированы, вы можете запускать их параллельно, чтобы повысить скорость на оборудовании с несколькими ядрами. См. test --parallel.

Хеширование паролей

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

PASSWORD_HASHERS = [
    'django.contrib.auth.hashers.MD5PasswordHasher',
]

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

Сохранение тестовой базы данных

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

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.1/topics/testing/overview/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API