Spec-Zone.ru › Django 1.11

Написание и запуск тестов

См. также

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

Данный документ разделен на два основных раздела. Во-первых, мы объясним, как писать тесты с 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 -Wall manage.py test. Флаг -Wall сообщает Python о том, что следует отображать предупреждения о устаревании функций. Django, подобно многим другим библиотекам Python, использует эти предупреждения, чтобы отметить случаи, когда функции будут удалены. Также могут быть отмечены участки вашего кода, которые не являются строго ошибочными, но могут быть улучшены.

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

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

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

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

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

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

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

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

При использовании SQLite в памяти с Python 3.4+ и SQLite 3.7.13+, общий кэш общий кэш будет включен, поэтому вы можете писать тесты с возможностью совместного использования базы данных между потоками.

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

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

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

См. также

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

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

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

  • Сначала выполняются все подклассы 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/1.11/topics/testing/overview/

Spec-Zone.ru

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