每次运行时都没有创建测试数据库的 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-dbnomigrations 指令实现的。

【讨论】:

【参考方案8】:

当前版本的 Django 有一个 --keepdb 参数,您可以将其传递给测试,这样数据库就不会在每次运行时被破坏和重建。

https://docs.djangoproject.com/en/3.0/ref/django-admin/#cmdoption-test-keepdb

【讨论】:

以上是关于每次运行时都没有创建测试数据库的 Django 单元测试的主要内容,如果未能解决你的问题,请参考以下文章

如何测试 django 数据库模式?

为啥 Django makemigrations 每次运行时都会检测到由于 help_text/verbose_name 属性中的重音而导致的更改?

Heroku:每次测功机重新启动时都会丢失 Django 数据库文件

C++ 问题我每次运行程序时都会得到“nan”作为输出

用于创建数据库、运行测试的 Django / postgres 设置

奇怪的错误 Django 运行时