Написание и запуск тестов
См. также
учебник по тестированию, справочник по инструментам тестирования и расширенные темы тестирования.
Этот документ разделен на два основных раздела. Сначала мы объясним, как писать тесты с 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. Каждая метка теста может быть полным полным путем к пакету, модулю, подклассу 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 в памяти с SQLite 3.7.13+ , кеш обмена (shared cache) включен, поэтому вы можете писать тесты с возможностью совместного использования базы данных между потоками.
Получение данных из вашей производственной базы данных при запуске тестов?
Если ваш код пытается получить доступ к базе данных при компиляции модулей, это произойдет *до* настройки тестовой базы данных, что может привести к непредсказуемым результатам. Например, если у вас есть запрос к базе данных в коде уровня модуля и существует реальная база данных, данные производства могут загрязнить ваши тесты. *В любом случае, не рекомендуется иметь такие запросы к базе данных во время импорта в вашем коде* - перепишите свой код, чтобы он этого не делал.
Это также относится к настраиваемым реализациям 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.0/topics/testing/overview/