Как запустить тесты для многоразового приложения django? - PullRequest
44 голосов
/ 01 октября 2010

Могу ли я запустить тесты для моего повторно используемого приложения Django без включения этого приложения в проект?

В моем приложении используются некоторые модели, поэтому необходимо указать параметры (TEST_)DATABASE_*.Где их хранить и как запускать тесты?

Для проекта Django я могу запускать тесты с manage.py test;когда я использую django-admin.py test с моим автономным приложением, я получаю:

Ошибка: невозможно импортировать настройки, поскольку переменная окружения DJANGO_SETTINGS_MODULE не определена.

Каковы лучшиепрактики здесь?

Ответы [ 5 ]

44 голосов
/ 04 сентября 2012

Правильное использование тестера Django (> = 1.4) выглядит следующим образом:

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 имеют в основном совместимые интерфейсы.

Для получения дополнительной информации вы должны обратиться к "Определение тестового бегуна "документы:

18 голосов
/ 03 октября 2010

Я закончил с таким решением (оно было вдохновлено решением, найденным в django-голосования):

Создать файл, например. '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) и не вредит тестам, запускаемым, когда приложение включено в более крупный проект.

10 голосов
/ 29 октября 2014

Для 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)

Некоторые параметры являются необязательными;они улучшают скорость или более реалистичную среду.

Второй аргумент указывает на текущий каталог.Он использует функцию предоставления пути к каталогу для обнаружения тестов под этим каталогом .

5 голосов
/ 02 октября 2010

Для моего многоразового приложения ( django-moderation ) я использую buildout. Я создаю example_project, я использую его с buildout для запуска тестов на нем. Я просто помещаю свое приложение в настройках example_project.

Когда я хочу установить все зависимости, используемые моим проектом, и запустить тесты, мне нужно только сделать следующее:

  • Выполнить: python bootstrap.py
  • Запуск компоновки:

    бен / Buildout

  • Запустите тесты для Django 1.1 и Django 1.2:

    бен / тест-1,1 бен / тест-1,2

Здесь вы можете найти учебное пособие по настройке многократно используемого приложения для использования buildout для развертывания и запуска тестов: http://jacobian.org/writing/django-apps-with-buildout/

Здесь вы найдете пример конфигурации buildout, который я использую в своем проекте:

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

1 голос
/ 01 апреля 2018

В чистом контексте 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')),
]

templates / base.html:

Если какой-либо из ваших тестов достигнет реальных представлений, шаблоны вашего приложения, вероятно, расширят проект base.html, поэтому этот файлдолжен существовать.В моем случае я только что создал пустой файл templates/base.html.

Теперь я могу запускать pytest -x -v из моего автономного каталога приложений многократного использования без проекта Django.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...