如何为 django 可重用应用程序启动测试?

Posted

技术标签:

【中文标题】如何为 django 可重用应用程序启动测试?【英文标题】:How to launch tests for django reusable app? 【发布时间】:2011-04-19 23:53:25 【问题描述】:

我可以在不将该应用程序合并到项目中的情况下为我的可重用 Django 应用程序启动测试吗?

我的应用使用了一些机型,所以需要提供(TEST_)DATABASE_*设置。我应该将它们存储在哪里以及如何启动测试?

对于 Django 项目,我可以使用 manage.py test 运行测试;当我将django-admin.py test 与我的独立应用程序一起使用时,我得到:

错误:无法导入设置, 因为环境变量 DJANGO_SETTINGS_MODULE 未定义。

这里有哪些最佳做法?

【问题讨论】:

Django 不需要项目。你在问什么?你运行django-admin.py test了吗?你观察到了什么? 对于 django 项目,我通过以下方式运行测试:manage.py 测试,当我使用 django-admin.py 时,我得到:错误:无法导入设置,因为环境变量 DJANGO_SETTINGS_MODULE 未定义。我相信这必须非常简单,但我坚持这样做。 【参考方案1】:

Django (>= 1.4) test runner的正确用法如下:

import django, sys
from django.conf import settings

settings.configure(DEBUG=True,
               DATABASES=
                    'default': 
                        'ENGINE': 'django.db.backends.sqlite3',
                    
                ,
               ROOT_URLCONF='myapp.urls',
               INSTALLED_APPS=('django.contrib.auth',
                              'django.contrib.contenttypes',
                              'django.contrib.sessions',
                              'django.contrib.admin',
                              'myapp',))

try:
    # Django < 1.8
    from django.test.simple import DjangoTestSuiteRunner
    test_runner = DjangoTestSuiteRunner(verbosity=1)
except ImportError:
    # Django >= 1.8
    django.setup()
    from django.test.runner import DiscoverRunner
    test_runner = DiscoverRunner(verbosity=1)

failures = test_runner.run_tests(['myapp'])
if failures:
    sys.exit(failures)

DjangoTestSuiteRunner 和 DiscoverRunner 具有大部分兼容的接口。

有关更多信息,您应该查阅“定义测试运行者”文档:

DjangoTestSuiteRunner (Django >=1.4, DiscoverRunner (Django >=1.8)

【讨论】:

【参考方案2】:

我以这样的解决方案结束(它的灵感来自 django-voting 中的解决方案):

创建文件,例如。测试目录中的“runtests.py”包含:

import os, sys
from django.conf import settings

DIRNAME = os.path.dirname(__file__)
settings.configure(DEBUG = True,
                   DATABASE_ENGINE = 'sqlite3',
                   DATABASE_NAME = os.path.join(DIRNAME, 'database.db'),
                   INSTALLED_APPS = ('django.contrib.auth',
                                     'django.contrib.contenttypes',
                                     'django.contrib.sessions',
                                     'django.contrib.admin',
                                     'myapp',
                                     'myapp.tests',))


from django.test.simple import run_tests

failures = run_tests(['myapp',], verbosity=1)
if failures:
    sys.exit(failures)

它允许通过python runtests.py 命令运行测试。 它不需要安装依赖项(例如 buildout),并且不会损害将应用程序合并到更大项目中时运行的测试。

【讨论】:

【参考方案3】:

对于 Django 1.7,它略有不同。假设你有以下 应用程序foo的目录结构:

foo
|── docs
|── foo
│   ├── __init__.py
│   ├── models.py
│   ├── urls.py
│   └── views.py
└── tests
    ├── foo_models
    │   ├── __init__.py
    │   ├── ...
    │   └── tests.py
    ├── foo_views 
    │   ├── __init__.py
    │   ├── ...
    │   └── tests.py
    ├── runtests.py
    └── urls.py

这就是 Django 项目本身构建其测试的方式。

您想使用以下命令在foo/tests/ 中运行所有测试:

python3 runtests.py

您还希望能够从 tests 的父目录运行命令,例如通过 Tox 或 Invoke,就像 python3 foo/tests/runtests.py

我在这里介绍的解决方案是可重复使用的,只需调整应用程序的名称foo(如果需要,还需要调整其他应用程序)。它们可以通过modify_settings 安装,因为它会错过数据库设置。

需要以下文件:

urls.py

"""
This urlconf exists because Django expects ROOT_URLCONF to exist. URLs
should be added within the test folders, and use TestCase.urls to set them.
This helps the tests remain isolated.
"""

urlpatterns = []

runtests.py

#!/usr/bin/env python3
import glob
import os
import sys

import django
from django.conf import settings
from django.core.management import execute_from_command_line


BASE_DIR = os.path.abspath(os.path.dirname(__file__))
sys.path.append(os.path.abspath(os.path.join(BASE_DIR, '..')))

# Unfortunately, apps can not be installed via ``modify_settings``
# decorator, because it would miss the database setup.
CUSTOM_INSTALLED_APPS = (
    'foo',
    'django.contrib.admin',
)

ALWAYS_INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)

ALWAYS_MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)


settings.configure(
    SECRET_KEY="django_tests_secret_key",
    DEBUG=False,
    TEMPLATE_DEBUG=False,
    ALLOWED_HOSTS=[],
    INSTALLED_APPS=ALWAYS_INSTALLED_APPS + CUSTOM_INSTALLED_APPS,
    MIDDLEWARE_CLASSES=ALWAYS_MIDDLEWARE_CLASSES,
    ROOT_URLCONF='tests.urls',
    DATABASES=
        'default': 
            'ENGINE': 'django.db.backends.sqlite3',
        
    ,
    LANGUAGE_CODE='en-us',
    TIME_ZONE='UTC',
    USE_I18N=True,
    USE_L10N=True,
    USE_TZ=True,
    STATIC_URL='/static/',
    # Use a fast hasher to speed up tests.
    PASSWORD_HASHERS=(
        'django.contrib.auth.hashers.MD5PasswordHasher',
    ),
    FIXTURE_DIRS=glob.glob(BASE_DIR + '/' + '*/fixtures/')

)

django.setup()
args = [sys.argv[0], 'test']
# Current module (``tests``) and its submodules.
test_cases = '.'

# Allow accessing test options from the command line.
offset = 1
try:
    sys.argv[1]
except IndexError:
    pass
else:
    option = sys.argv[1].startswith('-')
    if not option:
        test_cases = sys.argv[1]
        offset = 2

args.append(test_cases)
# ``verbosity`` can be overwritten from command line.
args.append('--verbosity=2')
args.extend(sys.argv[offset:])

execute_from_command_line(args)

有些设置是可选的;它们可以提高速度或更逼真的环境。

第二个参数指向当前目录。它使用feature of providing a path to a directory to discover tests below that directory。

【讨论】:

很好的答案!我在/tests/ 中添加了__init__.py 以使其正常工作。 在大多数情况下,我能够避免在tests 目录中为我的应用程序设置子目录,只需设置test_cases = '..' (以允许我遵循进行测试的约定.py 在应用程序文件夹中)。很好的答案!【参考方案4】:

对于我的可重用应用程序 (django-moderation),我使用 buildout。我创建了example_project,我用它和 buildout 来运行测试。我只是将我的应用程序放在example_project 的设置中。

当我想安装我的项目使用的所有依赖项并运行测试时,我只需要执行以下操作:

运行:python bootstrap.py

运行构建:

bin/构建

为 Django 1.1 和 Django 1.2 运行测试:

bin/test-1.1 bin/test-1.2

在这里您可以找到如何配置可重用应用程序以使用 buildout 进行部署和测试运行的教程:http://jacobian.org/writing/django-apps-with-buildout/

在这里您将找到我在项目中使用的示例构建配置:

http://github.com/dominno/django-moderation/blob/master//buildout.cfg

【讨论】:

感谢您提供有用的信息。看看这是否能解决我的问题(乍一看似乎很麻烦),但对于其他目的可能很有趣。【参考方案5】:

在纯 pytest 上下文中,为了提供足够的 Django 环境来让我的可重用应用程序在没有实际 Django 项目的情况下运行测试,我需要以下部分:

pytest.ini:

[pytest]
DJANGO_SETTINGS_MODULE = test_settings
python_files = tests.py test_*.py *_tests.py

test_settings.py:

# You may need more or less than what's shown here - this is a skeleton:

DATABASES = 
    'default': 
        'ENGINE': 'django.db.backends.sqlite3',
    


INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.messages',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.staticfiles',
    'todo',
)

ROOT_URLCONF = 'base_urls'

TEMPLATES = [
    
        'DIRS': ['path/to/your/templates'), ],
    
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

base_urls.py:

"""
This urlconf exists so we can run tests without an actual
Django project (Django expects ROOT_URLCONF to exist.)
It is not used by installed instances of this app.
"""

from django.urls import include, path

urlpatterns = [
    path('foo/', include('myapp.urls')),
]

模板/base.html:

如果您的任何测试达到实际视图,您的应用程序模板可能会扩展项目base.html,因此该文件必须存在。就我而言,我刚刚创建了一个空文件templates/base.html

我现在可以从我的独立可重用应用程序目录中运行 pytest -x -v,而无需 Django 项目。

【讨论】:

【参考方案6】:

我知道这是一个旧线程,但我发现如果您的可重用应用程序有一个文件“tests.py”,那么您可以在项目文件夹中创建一个tests.py,然后编写以下内容...

from reusableapp.tests import *

当你调用“python manage.py test”时,Django 会运行​​这些测试

【讨论】:

我将 print("running reusableapp tests...") 放在可重用应用程序的 tests.py 顶部,这样我可以看到正在运行哪些测试。

以上是关于如何为 django 可重用应用程序启动测试?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Electron 应用程序服务 Django

您如何为 angularjs 可重用组件打包资产?

如何在 Django 中重用可重用的应用程序

如何为 asp.net webapi 构建可重用的 .Net 客户端,包括 IQueryable 功能等

为可重用的 Django 应用程序创建迁移

Android Espresso - 如何为所有测试只运行一次设置