Модульные тесты ¶
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 requirements\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
...\> tox -l
py3
flake8
docs
isort
Тестирование с другими версиями 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 install
npm 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
. Это используется для проверки запросов, направленных к другим базам данных. Он должен использовать тот же механизм, что и база данных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
. Например :
$ ./runtests.py --start-at=wsgi
...\> runtests.py --start-at=wsgi
Вы также можете запустить тесты, начав после модуля первого уровня с опцией --start-after
. Например :
$ ./runtests.py --start-after=wsgi
...\> runtests.py --start-after=wsgi
Обратите внимание, что параметр --reverse
не влияет на параметры --start-at
и --start-after
. Кроме того, эти параметры нельзя использовать при указании имен тестов.
Запуск тестов Selenium ¶
Для некоторых тестов требуется Selenium и веб-браузер. Чтобы запустить эти тесты, вы должны установить пакет selenium и запустить тесты с опцией --selenium=<NAVIGATEURS>
. Например, если установлены Firefox и Google Chrome:
$ ./runtests.py --selenium=firefox,chrome
...\> runtests.py --selenium=firefox,chrome
См. Пакет selenium.webdriver для получения списка доступных браузеров.
Индикация --selenium
автоматически устанавливает --tags=selenium
запуск только тестов, требующих селен.
Некоторые браузеры (например, Chrome или Firefox) поддерживают тестирование без интерфейса, что может быть быстрее и стабильнее. Добавьте возможность --headless
активировать этот режим.
Запуск всех тестов ¶
Если вы хотите запустить полный набор тестов, вам нужно будет установить ряд зависимостей:
- аргон2- cffi 16.1.0+
- asgiref 3.2.10+ (обязательно)
- Bcrypt
- Docutils
- geoip2
- jinja2 2.7+
- NumPy
- Подушка 6.2.0+
- PyYAML
- pytz (обязательно)
- pywatchman
- Setuptools
- memcached , плюс поддерживаемая привязка Python
- gettext ( gettext и Windows )
- селен
- sqlparse 0.2.2+ (обязательно)
- tblib 1.5.0+
Вы можете найти эту зависимость в файлах пип зависимости в tests/requirements
исходном коде Джанго каталога , и вы можете установить их так:
$ 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, вам необходимо настроить пространственную базу данных и установить геопространственные библиотеки .
Эти зависимости не являются обязательными. Если один из них отсутствует, соответствующие тесты будут пропущены.
Для запуска некоторых тестов autoreload
вам необходимо установить службу 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 ¶
Тесты добавленных приложений можно найти в каталоге tests/
, обычно в <nom_app>_tests
. Например, тесты для могут contrib.auth
быть найдены в tests/auth_tests
.
Устранение неполадок ¶
Набор тестов зависает или показывает ошибки на master
ветке ¶
Убедитесь, что у вас есть последний выпуск поддерживаемой версии 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
целей в качестве параметров:
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)