Django自带了一个测试套件,在代码库的tests
目录中。 这是我们的政策,以确保所有测试在任何时候通过。
我们赞赏任何和所有的贡献的测试套件!
Django测试使用Django附带的测试基础架构来测试应用程序。 有关如何编写新测试的说明,请参见Writing and running tests。
首先,在gitHub上的fork Django。
其次,创建并激活一个虚拟环境。 如果您不熟悉如何做,请阅读我们的contributing tutorial。
接下来,克隆你的fork,安装一些要求,然后运行测试:
$ git clone git@github.com:YourGitHubName/django.git django-repo
$ cd django-repo/tests
$ pip install -e ..
$ pip install -r requirements/py3.txt # Python 2: py2.txt
$ ./runtests.py
安装要求可能需要您的计算机未安装的某些操作系统软件包。 通常可以通过对最后一行错误消息进行Web搜索来确定要安装的软件包。 如果需要,尝试将搜索查询添加到您的操作系统。
如果您无法安装需求,则可以跳过该步骤,除了Python 2之外,您必须pip 安装 mock 。
有关安装可选测试依赖关系的详细信息,请参阅Running all the tests。 如果您没有安装可选的依赖关系,则会跳过需要的测试。
运行测试需要一个Django设置模块来定义要使用的数据库。 为了便于开始,Django提供并使用了一个使用SQLite数据库的示例设置模块。 请参阅Using another settings module了解如何使用其他设置模块来运行不同数据库的测试。
Windows用户
我们推荐使用Git Bash来运行使用上述方法的测试。
有问题吗? 有关常见问题,请参阅Troubleshooting。
tox
¶运行测试Tox是用于在不同虚拟环境中运行测试的工具。 Django包括一个基本的tox.ini
,可以自动执行我们的构建服务器对拉请求执行的一些检查。 To run the unit tests
and other checks (such as import sorting, the
documentation spelling checker, and
code formatting), install and run the tox
command from any place in the Django source tree:
$ pip install tox
$ tox
默认情况下,tox
运行带有SQLite捆绑测试设置文件的测试套件,flake8
,isort
以及文档拼写检查器。 除了本文档中其他地方所指定的系统依赖性之外,命令python2
和python3
必须位于您的路径上,并链接到相应的Python版本。 默认环境列表可以看出如下:
$ tox -l
py3
flake8
docs
isort
除了默认环境之外,tox
还支持对其他版本的Python和其他数据库后端运行单元测试。 由于Django的测试套件不会捆绑除SQLite之外的数据库后端的设置文件,因此您必须create and provide your own test settings。 例如,要使用PostgreSQL在Python 3.5上运行测试:
$ tox -e py35-postgres -- --settings=my_postgres_settings
该命令设置一个Python 3.5虚拟环境,安装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
Django在某些contrib应用程序中包含一组JavaScript unit tests。 JavaScript测试在默认情况下不使用tox
运行,因为它们需要安装Node.js,并且绝大多数补丁都不需要。 使用tox
运行JavaScript测试:
$ tox -e javascript
该命令运行npm install
,以确保测试要求是最新的,然后运行npm 测试 T5> T3>。
settings
module¶随附的设置模块(tests/test_sqlite.py
)允许您使用SQLite运行测试套件。 如果要使用其他数据库运行测试,则需要定义自己的设置文件。 某些测试(例如contrib.postgres
的测试)特定于特定的数据库后端,如果使用不同的后端运行,则将被跳过。
要使用不同的设置运行测试,请确保模块位于PYTHONPATH
上,并使用--settings
传递模块。
任何测试设置模块中的DATABASES
设置需要定义两个数据库:
default
数据库。 该数据库应使用您要用于主要测试的后端。other
的数据库。 other
数据库用于测试查询可以定向到不同的数据库。 该数据库应使用与default
相同的后端,并且必须具有不同的名称。如果您使用的不是SQLite的后端,则需要为每个数据库提供其他详细信息:
测试数据库通过在DATABASES
中定义的数据库的NAME
设置的值之前加上test_
测试完成后,将删除这些测试数据库。
您还需要确保数据库使用UTF-8作为默认字符集。 如果您的数据库服务器不使用UTF-8作为默认字符集,则需要在适用数据库的测试设置字典中包含CHARSET
的值。
Django的整个测试套件需要一段时间才能运行,并且运行每一个测试可能是多余的,如果,你刚刚添加一个测试Django,你想运行快速,而不运行其他。 您可以通过在命令行上将测试模块的名称附加到runtests.py
来运行单元测试的子集。
例如,如果您只想对通用关系和国际化运行测试,请键入:
$ ./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.test_lazy_objects
一些测试需要Selenium和Web浏览器。 要运行这些测试,您必须安装selenium软件包,并使用--selenium=<BROWSERS>
选项运行测试。 例如,如果您安装了Firefox和Google Chrome,请执行以下操作:
$ ./runtests.py --selenium=firefox,chrome
有关可用浏览器的列表,请参阅selenium.webdriver包。
指定--selenium
自动设置--tags=selenium
仅运行需要硒的测试。
如果你想运行全套的测试,你需要安装一些依赖:
您可以在Django源代码树的tests/requirements
目录中的pip需求文件中找到这些依赖关系,并安装它们,如下所示:
$ pip install -r tests/requirements/py3.txt # Python 2: py2.txt
如果在安装期间遇到错误,则您的系统可能缺少一个或多个Python包的依赖关系。 请参阅失败的软件包文档或使用您遇到的错误消息搜索Web。
您还可以使用oracle.txt
,mysql.txt
或postgres.txt
安装您选择的数据库适配器。
如果要测试memcached缓存后端,还需要定义指向memcached实例的CACHES
设置。
要运行GeoDjango测试,您需要setup a spatial database and install the Geospatial libraries。
这些依赖关系中的每一个都是可选的。 如果你缺少任何一个,相关的测试将被跳过。
鼓励贡献者在测试套件上运行覆盖,以识别需要额外测试的区域。 覆盖工具的安装和使用在testing code coverage中进行了说明。
覆盖范围应在单一过程中运行,以获得准确的统计数据。 要使用标准测试设置在Django测试套件上运行覆盖率:
$ coverage run ./runtests.py --settings=test_sqlite --parallel=1
运行coverage后,通过运行以下命令生成html报告:
$ coverage html
当运行Django测试的coverage时,包含的.coveragerc
设置文件将coverage_html
定义为报告的输出目录,并排除与结果不相关的几个目录(测试代码或Django中包含的外部代码)。
可以在tests/
目录中找到contrib应用程序的测试,通常在<app_name>_tests
下。 例如,contrib.auth
的测试位于tests/auth_tests
中。
UnicodeEncodeError
¶如果未安装locales
包,则某些测试将失败,并显示UnicodeEncodeError
。
您可以在基于Debian的系统上解决此问题,例如,运行:
$ apt-get install locales
$ dpkg-reconfigure locales
您可以通过配置您的shell的区域设置来解决macOS系统的问题:
$ export LANG="en_US.UTF-8"
$ export LC_ALL="en_US.UTF-8"
运行locale
命令确认更改。 或者,将这些导出命令添加到您的shell的启动文件(例如Bash的~/.bashrc
),以避免重新输入。
如果测试通过时孤立运行,但在整个套件中失败,我们有一些工具来帮助分析问题。
--bisect
的runtests.py
选项将运行失败的测试,同时将测试集减半,它在每次迭代中一起运行,通常可以识别一个小可能与故障相关的测试次数。
例如,假设自己工作的失败测试是ModelTest.test_eq
,然后使用:
$ ./runtests.py --bisect basic.tests.ModelTest.test_eq
将尝试确定干扰给定的测试。 首先,测试使用测试套件的前半部分运行。 如果发生故障,则测试套件的前半部分分成两组,然后每组使用指定的测试运行。 如果测试套件的前半部分没有故障,则测试套件的后半部分将按照指定的测试运行,并如前所述进行适当的拆分。 该过程重复,直到该组失败测试最小化。
--pair
选项运行给定的测试以及套件中的每个其他测试,让您检查另一个测试是否有导致失败的副作用。 所以:
$ ./runtests.py --pair basic.tests.ModelTest.test_eq
将test_eq
与每个测试标签配对。
对于--bisect
和--pair
,如果您已经怀疑哪些情况可能导致故障,您可以将测试限制为交叉分析specifying further test labels:
$ ./runtests.py --pair basic.tests.ModelTest.test_eq queries transactions
您还可以使用--reverse
选项反向运行任何一组测试,以验证以不同顺序执行测试不会导致任何故障:
$ ./runtests.py basic --reverse
如果希望检查在失败测试中运行的SQL,可以使用--debug-sql
选项打开SQL logging。 如果将其与--verbosity=2
组合,则将输出所有SQL查询:
$ ./runtests.py basic --debug-sql
默认情况下,测试与每个核心的一个进程并行运行。 但是,当测试并行运行时,您只会看到任何测试失败的截断回溯。 您可以使用--parallel
选项调整此行为:
$ ./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。
isolation_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)
2017年9月6日