Spec-Zone.ru › Django 1.10

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

См. также

учебник по тестированию, справочник по инструментам тестирования и расширенные темы по тестированию.

Этот документ разделен на два основных раздела. Сначала мы объясним, как писать тесты с 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 переупорядочивает тесты следующим образом:

  • Сначала выполняются все 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.

Изменено в Django 1.9.

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

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

Spec-Zone.ru

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