Модульные тесты

Django поставляется с собственным набором тестов в testsкаталоге базы кода. Наша политика - обеспечить постоянное прохождение всех тестов.

Мы ценим любой вклад в набор тестов!

Все тесты Django используют инфраструктуру тестирования, которая поставляется с Django для тестирования приложений. См. Раздел Написание и выполнение тестов для объяснения того, как писать новые тесты.

Запуск модульных тестов

Быстрый старт

Сначала создайте вилку Django на GitHub .

Во-вторых, создайте и активируйте виртуальную среду. Если вы не знаете, как это сделать, прочтите наше дополнительное руководство .

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

$ git clone https://github.com/YourGitHubName/django.git django-repo
$ cd django-repo/tests
$ python -m pip install -e ..
$ python -m pip install -r requirements/py3.txt
$ ./runtests.py
... \> git clone https://github.com/YourGitHubName/django.git django-repo
 ... \>  cd django-repo \ tests
 ... \> py -m pip install -e ..
 .. . \> py -m pip install -r требования \ py3.txt
 ... \> runtests.py 

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

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

Для запуска тестов требуется модуль настроек Django, который определяет используемые базы данных. Чтобы помочь вам начать работу, Django предоставляет и использует образец модуля настроек, который использует базу данных SQLite. См. Раздел Использование другого модуля настроек, чтобы узнать, как использовать другой модуль настроек для запуска тестов с другой базой данных.

Возникли проблемы? См. Раздел « Устранение неполадок» для ознакомления с некоторыми распространенными проблемами.

Запуск тестов с использованием tox

Tox - это инструмент для запуска тестов в различных виртуальных средах. Django включает базовый пакет, tox.iniкоторый автоматизирует некоторые проверки, которые наш сервер сборки выполняет при запросах на вытягивание. Чтобы запустить модульные тесты и другие проверки (например, сортировку импорта , проверку орфографии в документации и форматирование кода ), установите и запустите tox команду из любого места в дереве исходного кода Django:

$ python -m pip install tox
$ tox
... \> py -m pip install tox
 ... \> tox

По умолчанию, toxзапускает набор тестов с помощью прилагаемого Тестировать настройки файла для SQLite, flake8, isort, и документация проверки орфографии. В дополнение к системным зависимостям, указанным в другом месте в этой документации, команда python3должна быть на вашем пути и связана с соответствующей версией Python. Список сред по умолчанию можно увидеть следующим образом:

$ tox -l
py3
flake8
docs
isort>=5.1.0
... \> tox
 -l
 py3 flake8 
документы 
isort> = 5.1.0

Тестирование других версий Python и бэкендов баз данных

В дополнение к средам по умолчанию toxподдерживает выполнение модульных тестов для других версий Python и других баз данных. Поскольку набор тестов Django не объединяет файл настроек для серверной части базы данных, кроме SQLite, вы должны создать и предоставить свои собственные настройки теста . Например, чтобы запустить тесты на Python 3.7 с использованием PostgreSQL:

$ tox -e py37-postgres -- --settings=my_postgres_settings
...\> tox -e py37-postgres -- --settings=my_postgres_settings

Эта команда настраивает виртуальную среду Python 3.7, устанавливает зависимости набора тестов Django (в том числе для PostgreSQL) и вызывает runtests.pyс предоставленными аргументами (в данном случае --settings=my_postgres_settings).

В оставшейся части этой документации показаны команды для запуска тестов без tox, однако, любой параметр, переданный в, runtests.pyтакже можно передать tox, добавив к списку аргументов префикс --, как указано выше.

Tox также уважает DJANGO_SETTINGS_MODULEпеременная окружения, если установлена. Например, следующая команда эквивалентна приведенной выше команде:

$ DJANGO_SETTINGS_MODULE=my_postgres_settings tox -e py35-postgres

Пользователи Windows должны использовать:

...\> set DJANGO_SETTINGS_MODULE=my_postgres_settings
...\> tox -e py35-postgres

Запуск тестов JavaScript

Django включает набор модульных тестов JavaScript для функций в определенных приложениях contrib. По умолчанию тесты JavaScript не запускаются, toxпотому что они требуют Node.jsустановки и не нужны для большинства исправлений. Чтобы запустить тесты JavaScript, используйте tox:

$ tox -e javascript
...\> tox -e javascript

Эта команда запускается, чтобы убедиться, что требования к тестам актуальны, а затем запускается .npm installnpm test

Запуск тестов с использованием django-docker-box

django-docker-box позволяет запускать набор тестов Django для всех поддерживаемых баз данных и версий Python. См. Страницу проекта django-docker-box для получения инструкций по установке и использованию.

Использование другого settingsмодуля

Включенный модуль настроек ( tests/test_sqlite.py) позволяет запускать набор тестов с помощью SQLite. Если вы хотите запустить тесты с использованием другой базы данных, вам нужно будет определить свой собственный файл настроек. Некоторые тесты, такие как тесты, contrib.postgresотносятся к конкретной серверной части базы данных и будут пропущены при запуске с другой серверной частью.

Чтобы запустить тесты с разными настройками, убедитесь, что модуль установлен на вашем PYTHONPATHи передайте модуль с помощью --settings.

Параметр DATABASESв любом модуле настроек теста должен определять две базы данных:

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

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

  • Параметр USERдолжен указать существующую учетную запись пользователя для базы данных. Этому пользователю необходимо разрешение на выполнение, чтобы можно было создать тестовую базу данных.CREATE DATABASE
  • Параметр PASSWORDдолжен предоставить пароль для USERуказанного.

Тестовые базы данных получают свои имена, добавляя их test_к значению NAMEнастроек для баз данных, определенных в DATABASES. Эти тестовые базы данных удаляются по завершении тестов.

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

Выполняется только часть тестов

Для запуска всего набора тестов Django требуется время, и запуск каждого отдельного теста может быть избыточным, если, скажем, вы просто добавили тест в Django, который вы хотите запустить быстро, не выполняя все остальное. Вы можете запустить подмножество модульных тестов, добавив имена тестовых модулей runtests.pyв командную строку.

Например, если вы хотите запустить тесты только для общих отношений и интернационализации, введите:

$ ./runtests.py --settings=path.to.settings generic_relations i18n
...\> runtests.py --settings=path.to.settings generic_relations i18n

Как узнать названия отдельных тестов? Загляните внутрь tests/- в каждом имени каталога есть название теста.

Если вы хотите запустить только определенный класс тестов, вы можете указать список путей к отдельным тестовым классам. Например, для запуска TranslationTests из i18nмодуля, типа:

$ ./runtests.py --settings=path.to.settings i18n.tests.TranslationTests
...\> runtests.py --settings=path.to.settings i18n.tests.TranslationTests

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

$ ./runtests.py --settings=path.to.settings i18n.tests.TranslationTests.test_lazy_objects
...\> runtests.py --settings=path.to.settings i18n.tests.TranslationTests.test_lazy_objects

Вы можете запускать тесты, начиная с указанного модуля верхнего уровня с помощью --start-at option. Например:

$ ./runtests.py --start-at=wsgi
...\> runtests.py --start-at=wsgi

Вы также можете запускать тесты, начиная с указанного модуля верхнего уровня с помощью --start-afteroption. Например:

$ ./runtests.py --start-after=wsgi
...\> runtests.py --start-after=wsgi

Обратите внимание, что этот --reverseпараметр не влияет на параметры --start-atили --start-after. Более того, эти параметры нельзя использовать с тестовыми этикетками.

Запуск тестов Selenium

Для некоторых тестов требуется Selenium и веб-браузер. Чтобы запустить эти тесты, вы должны установить пакет selenium и запустить тесты с --selenium=<BROWSERS>опцией. Например, если у вас установлены Firefox и Google Chrome:

$ ./runtests.py --selenium=firefox,chrome
...\> runtests.py --selenium=firefox,chrome

Список доступных браузеров см. В пакете selenium.webdriver .

При указании --seleniumавтоматически --tags=seleniumзапускаются только тесты, требующие селен.

Некоторые браузеры (например, Chrome или Firefox) поддерживают автономное тестирование, которое может быть быстрее и стабильнее. Добавьте --headlessвозможность включить этот режим.

Запуск всех тестов

Если вы хотите запустить полный набор тестов, вам необходимо установить ряд зависимостей:

Вы можете найти эти зависимости в файлах требований pip внутри tests/requirementsкаталога исходного дерева Django и установить их следующим образом:

$ python -m pip install -r tests/requirements/py3.txt
...\> py -m pip install -r tests\requirements\py3.txt

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

Кроме того, можно установить адаптер базы данных (ы) по вашему выбору , используя oracle.txt, mysql.txtили postgres.txt.

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

Чтобы запустить тесты GeoDjango, вам необходимо настроить пространственную базу данных и установить библиотеки геопространственных данных .

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

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

Покрытие кода

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

Чтобы получить точную статистику, покрытие должно выполняться в рамках единого процесса. Чтобы запустить покрытие в тестовом наборе Django с использованием стандартных настроек тестирования:

$ coverage run ./runtests.py --settings=test_sqlite --parallel=1
...\> coverage run runtests.py --settings=test_sqlite --parallel=1

После запуска покрытия сгенерируйте отчет в формате html, запустив:

$ coverage html
...\> coverage html

При выполнении покрытия для тестов Django включенный .coveragerc файл настроек определяет coverage_htmlкак выходной каталог для отчета, а также исключает несколько каталогов, не имеющих отношения к результатам (тестовый код или внешний код, включенный в Django).

Приложения Contrib

Тесты для приложений contrib можно найти в tests/каталоге, обычно в <app_name>_tests. Например, тесты для contrib.authрасположены tests/auth_tests.

Устранение неполадок

Набор тестов зависает или показывает сбои в mainветке

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

В macOS (High Sierra и более новые версии) вы можете увидеть это сообщение в журнале, после чего тесты зависают:

objc[42074]: +[__NSPlaceholderDate initialize] may have been in progress in
another thread when fork() was called.

Чтобы избежать этого, установите OBJC_DISABLE_INITIALIZE_FORK_SAFETYпеременную среды, например:

$ OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES ./runtests.py

Или добавьте в файл запуска вашей оболочки (например ).export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES~/.profile

Множество неудачных тестов с UnicodeEncodeError

Если localesпакет не установлен, некоторые тесты завершатся ошибкой с расширением UnicodeEncodeError.

Вы можете решить эту проблему в системах на основе Debian, например, запустив:

$ apt-get install locales
$ dpkg-reconfigure locales

Вы можете решить эту проблему для систем macOS, настроив локаль своей оболочки:

$ export LANG="en_US.UTF-8"
$ export LC_ALL="en_US.UTF-8"

Запустите localeкоманду, чтобы подтвердить изменение. При желании добавьте эти команды экспорта в файл запуска вашей оболочки (например, ~/.bashrcдля Bash), чтобы не вводить их повторно.

Тесты, которые терпят неудачу только в сочетании

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

--bisectВариант runtests.pyбудет работать тест неисправного , а вдвое сократить набор тестов он запускается вместе с на каждой итерации, часто делает возможным идентифицировать небольшое количество тестов , которые могут быть связаны с провалом.

Например, предположим, что неудачный тест, который работает сам по себе ModelTest.test_eq, затем использует:

$ ./runtests.py --bisect basic.tests.ModelTest.test_eq
...\> runtests.py --bisect basic.tests.ModelTest.test_eq

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

Эта --pairопция запускает данный тест вместе с каждым другим тестом из набора, позволяя вам проверить, есть ли у другого теста побочные эффекты, вызывающие сбой. Так:

$ ./runtests.py --pair basic.tests.ModelTest.test_eq
...\> runtests.py --pair basic.tests.ModelTest.test_eq

будет сопрягаться test_eqс каждой тестовой меткой.

С обоими --bisectи --pair, если вы уже подозреваете, какие случаи могут быть причиной сбоя, вы можете ограничить перекрестный анализ тестов, указав дополнительные метки тестов после первого:

$ ./runtests.py --pair basic.tests.ModelTest.test_eq queries transactions
...\> runtests.py --pair basic.tests.ModelTest.test_eq queries transactions

Вы также можете попробовать запустить любой набор тестов в обратном порядке, используя эту --reverse опцию, чтобы убедиться, что выполнение тестов в другом порядке не вызывает никаких проблем:

$ ./runtests.py basic --reverse
...\> runtests.py basic --reverse

Наблюдение за выполнением SQL-запросов во время теста

Если вы хотите проверить выполняемый SQL в неудачных тестах, вы можете включить ведение журнала SQL, используя --debug-sqlопцию. Если вы объедините это с --verbosity=2, все запросы SQL будут выведены:

$ ./runtests.py basic --debug-sql
...\> runtests.py basic --debug-sql

Просмотр полного отслеживания неудачного теста

По умолчанию тесты выполняются параллельно, по одному процессу на ядро. Однако, когда тесты выполняются параллельно, вы увидите только усеченную трассировку для любых сбоев теста. Вы можете настроить это поведение с помощью --parallelопции:

$ ./runtests.py basic --parallel=1
...\> runtests.py basic --parallel=1

Вы также можете использовать DJANGO_TEST_PROCESSES переменная окружения для этой цели.

Советы по написанию тестов

Регистрация изолирующей модели

Чтобы избежать загрязнения глобального appsреестра и предотвращения ненужного создания таблиц, модели, определенные в методе тестирования, должны быть привязаны к временному Appsэкземпляру:

from django.apps.registry import Apps
from django.db import models
from django.test import SimpleTestCase

class TestModelDefinition(SimpleTestCase):
    def test_model_definition(self):
        test_apps = Apps(['app_label'])

        class TestModel(models.Model):
            class Meta:
                apps = test_apps
        ...
django.test.utils.isolate_apps( * app_labels , attr_name = None , kwarg_name = None )

Поскольку этот шаблон включает в себя множество шаблонов, Django предоставляет isolate_apps()декоратор. Он используется так:

from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps

class TestModelDefinition(SimpleTestCase):
    @isolate_apps('app_label')
    def test_model_definition(self):
        class TestModel(models.Model):
            pass
        ...

Параметр app_label

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

Чтобы убедиться, что модели, определенные в контексте isolate_apps()экземпляров, правильно установлены, вы должны передать набор целевых в app_labelкачестве аргументов:

tests / app_label / tests.py
from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps

class TestModelDefinition(SimpleTestCase):
    @isolate_apps('app_label', 'other_app_label')
    def test_model_definition(self):
        # This model automatically receives app_label='app_label'
        class TestModel(models.Model):
            pass

        class OtherAppModel(models.Model):
            class Meta:
                app_label = 'other_app_label'
        ...

Декоратор также может применяться к классам:

from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps

@isolate_apps('app_label')
class TestModelDefinition(SimpleTestCase):
    def test_model_definition(self):
        class TestModel(models.Model):
            pass
        ...

Временный Appsэкземпляр, используемый для изоляции регистрации модели, может быть получен как атрибут при использовании в качестве декоратора класса с помощью attr_nameпараметра:

from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps

@isolate_apps('app_label', attr_name='apps')
class TestModelDefinition(SimpleTestCase):
    def test_model_definition(self):
        class TestModel(models.Model):
            pass
        self.assertIs(self.apps.get_model('app_label', 'TestModel'), TestModel)

Или в качестве аргумента тестового метода при использовании в качестве декоратора метода с помощью kwarg_nameпараметра:

from django.db import models
from django.test import SimpleTestCase
from django.test.utils import isolate_apps

class TestModelDefinition(SimpleTestCase):
    @isolate_apps('app_label', kwarg_name='apps')
    def test_model_definition(self, apps):
        class TestModel(models.Model):
            pass
        self.assertIs(apps.get_model('app_label', 'TestModel'), TestModel)

Copyright ©2021 All rights reserved