每次运行时都没有创建测试数据库的 Django 单元测试
Posted
技术标签:
【中文标题】每次运行时都没有创建测试数据库的 Django 单元测试【英文标题】:Django unit test without creating test database every time I run 【发布时间】:2011-11-04 02:11:13 【问题描述】:似乎“manage.py test”每次运行测试时都会创建测试数据库。有没有办法防止在我每次运行测试时创建测试数据库但只是截断数据(刷新)?
我的表大约有 40 个表(即使是单个应用程序,而不是整个项目),每次运行测试都让我感到恶心。
【问题讨论】:
【参考方案1】:从 Django 1.8 开始,您可以在调用 manage.py 时使用 --keepdb 标志
Django 1.8 中的新功能:您可以防止测试数据库被 通过在测试命令中添加 --keepdb 标志 来销毁。这会 在运行之间保留测试数据库。如果数据库没有 存在,它将首先被创建。也将应用任何迁移 为了使其保持最新状态。 (https://docs.djangoproject.com/en/1.8/topics/testing/overview/#the-test-database)
所以您的调用可能如下所示:
python manage.py test --keepdb
或者使用简写 -k 它可能看起来像这样:
python manage.py test -k
【讨论】:
对于带有默认测试套件的现代 Django(1.8 或更高版本) - 这是最简单的。 即使使用 keepdb,django 也坚持每次都运行迁移 @Matt 如果测试数据库不存在,它将在第一次运行时创建,然后为每次后续运行保留。在运行测试套件之前,任何未应用的迁移也将应用于测试数据库。 django-docs @Matt 但是是的,每次运行测试时都会应用迁移(请参阅django-source 以供参考)。但是,以更高的详细模式 (python manage.py test -k --verbosity 2
) 运行测试,您将看到迁移仅被检查,但如果之前已应用且在测试运行之间未更改,则不会重新应用。【参考方案2】:
根据您的需要,您有几个选择:
您可以编写自定义测试运行程序或调整默认运行程序:https://docs.djangoproject.com/en/1.6/topics/testing/advanced/#other-testing-frameworks
你可以使用SimpleTestCase
还有像 django-test-utils 这样的附加组件(虽然我不确定那个特定的是否适用于现代 Django 版本)。
或者,为了加快速度,您可以使用 SQLite's in-memory database 或创建您的 test database in RAM disk (like tmpfs or ramfs) - 实际上这与使用其他技术是正交的。
【讨论】:
【参考方案3】:django-nose 支持复用数据库:
https://github.com/django-nose/django-nose#enabling-database-reuse
但是,请务必阅读 cmets:
一个新的问题是,每当您的数据库架构发生变化时,您 下次运行测试时应该关闭该标志。这将提示 测试运行程序重新初始化测试数据库。
此外,REUSE_DB 与离开的 TransactionTestCases 不兼容 数据库中的垃圾,所以一定要让你的 TransactionTestCases 卫生 (见下文)如果你想使用它。
【讨论】:
【参考方案4】:如果有更多的南迁移,以下解决方案也将减少数据库创建时间。在单元测试期间,运行 syncdb 而不是运行所有的南迁移会快得多。
SOUTH_TESTS_MIGRATE = False # 禁用迁移并使用 syncdb 而是
【讨论】:
【参考方案5】:你也许可以试试test runner
例子:
首先,创建test_runners.py
from django.test.runner import DiscoverRunner
class NoDbTestRunner(DiscoverRunner):
def setup_databases(self, **kwargs):
""" Override the database creation defined in parent class """
pass
def teardown_databases(self, old_config, **kwargs):
""" Override the database teardown defined in parent class """
pass
然后在settings.py
中声明上面的runner
TEST_RUNNER = 'api.tests.test_runners.NoDbTestRunner'
【讨论】:
【参考方案6】:我猜这不是最佳实践,但作为解决方法,我已经在应用程序的 management/commands 目录中创建了几个不同的测试程序。
https://docs.djangoproject.com/en/1.7/howto/custom-management-commands/
例如,我现在正在开发一个需要一些高级 Postgres 功能(不能使用 Sqlite)的应用程序,因此我没有在 test.py 中创建测试函数,而是在 myapp/management/commands/ 中创建了 test_process.py
【讨论】:
【参考方案7】:您可能希望pytest
作为测试运行程序。配置示例如下。
示例pytest.ini
文件:
[pytest]
norecursedirs=
*.egg
.git
.tox
.env
_sass
build
dist
migrations
fabfile
.tox
python_files =
test_*.py
tests.py
DJANGO_SETTINGS_MODULE=settings.dev
addopts=
--reuse-db
--nomigrations
--cov=your_app
--ignore=.tox
--ignore=fabfile
--ignore=scripts
--ignore=settings
--ignore=tmp
--cov-report=html
--cov-report=term
--cov-report=annotate
示例runtests.py
文件:
#!/usr/bin/env python
import os
import sys
import pytest
def main():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings.dev")
return pytest.main()
if __name__ == '__main__':
sys.exit(main())
示例requirements.txt
文件:
pytest==3.0.2
pytest-django==2.9.1
pytest-cov==2.2.1
运行测试:
./runtests.py
注意,该效果是通过reuse-db
和nomigrations
指令实现的。
【讨论】:
【参考方案8】:当前版本的 Django 有一个 --keepdb 参数,您可以将其传递给测试,这样数据库就不会在每次运行时被破坏和重建。
https://docs.djangoproject.com/en/3.0/ref/django-admin/#cmdoption-test-keepdb
【讨论】:
以上是关于每次运行时都没有创建测试数据库的 Django 单元测试的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Django makemigrations 每次运行时都会检测到由于 help_text/verbose_name 属性中的重音而导致的更改?
Heroku:每次测功机重新启动时都会丢失 Django 数据库文件