10 ответов:
вы можете поставить свои тесты в
tests/подкаталог приложения (а неtests.pyfile), и включитьtests/models.pyс тестовыми моделями.затем предоставьте тестовый скрипт (пример) это включает в себя ваш
tests/"приложения" вINSTALLED_APPS. (Это не работает при запуске тестов приложений из реального проекта, в котором не будет приложения тестов вINSTALLED_APPS, но я редко считаю полезным запускать многоразовые тесты приложений из проекта, а Django 1.6+ не делает по умолчанию.)(Примечание: альтернативный динамический метод, описанный ниже, работает только в Django 1.1+, если ваш тестовый случай подклассы
TransactionTestCase- что значительно замедляет ваши тесты - и больше не работает вообще в Django 1.7+. Он остался здесь только для исторического интереса; не используйте его.)в начале ваших тестов (т. е. в методе настройки или в начале набора тестов) вы можете динамически добавлять
"myapp.tests"к установке INSTALLED_APPS, и затем сделайте следующее:from django.core.management import call_command from django.db.models import loading loading.cache.loaded = False call_command('syncdb', verbosity=0)затем в конце ваших тестов вы должны очистить, восстановив старую версию INSTALLED_APPS и снова очистив кэш приложения.
этот класс инкапсулирует шаблон, чтобы он не загромождал ваш тестовый код так же сильно.
ответ@paluh требует добавления нежелательного кода в нетестовый файл, и по моему опыту, решение @carl не работает с django.тест.TestCase, который необходим для использования светильников. Если вы хотите использовать django.тест.TestCase, вам нужно убедиться, что вы вызываете syncdb перед загрузкой светильников. Для этого необходимо переопределить метод _pre_setup (недостаточно поместить код в метод установки). Я использую свою собственную версию TestCase, которая позволяет мне добавлять приложения с тестовыми моделями. Он определяется как следует:
from django.conf import settings from django.core.management import call_command from django.db.models import loading from django import test class TestCase(test.TestCase): apps = () def _pre_setup(self): # Add the models to the db. self._original_installed_apps = list(settings.INSTALLED_APPS) for app in self.apps: settings.INSTALLED_APPS.append(app) loading.cache.loaded = False call_command('syncdb', interactive=False, verbosity=0) # Call the original method that does the fixtures etc. super(TestCase, self)._pre_setup() def _post_teardown(self): # Call the original method. super(TestCase, self)._post_teardown() # Restore the settings. settings.INSTALLED_APPS = self._original_installed_apps loading.cache.loaded = False
это решение работает только для более ранних версий
django(ранее1.7). Вы можете легко проверить свою версию:import django django.VERSION < (1, 7)оригинальный ответ:
Это довольно странно, но форма меня работает очень простой шаблон:
- добавить tests.py к приложению, которое вы собираетесь проверить,
- в этом файле просто определите тестовые модели,
- ниже поместите свой тестовый код (определение doctest или TestCase),
ниже я поместите некоторый код, который определяет модель статьи, которая нужна только для тестов (она существует в someapp/tests.py и я могу проверить это только с помощью: ./manage.py проверьте someapp ):
class Article(models.Model): title = models.CharField(max_length=128) description = models.TextField() document = DocumentTextField(template=lambda i: i.description) def __unicode__(self): return self.title __test__ = {"doctest": """ #smuggling model for tests >>> from .tests import Article #testing data >>> by_two = Article.objects.create(title="divisible by two", description="two four six eight") >>> by_three = Article.objects.create(title="divisible by three", description="three six nine") >>> by_four = Article.objects.create(title="divisible by four", description="four four eight") >>> Article.objects.all().search(document='four') [<Article: divisible by two>, <Article: divisible by four>] >>> Article.objects.all().search(document='three') [<Article: divisible by three>] """}модульные тесты также работают с таким определением модели.
Я выбрал несколько иной, хотя и более сопряженный, подход к динамическому созданию моделей только для тестирования.
Я держу все мои тесты в
testsподкаталог, который живет в моемfilesприложение. Элемент наtestsподкаталог содержит мои тестовые модели. Связанная часть приходит сюда, где мне нужно добавить следующее К моемуsettings.pyfile:# check if we are testing right now TESTING = 'test' in sys.argv if TESTING: # add test packages that have models INSTALLED_APPS += ['files.tests',]Я также установил db_table в моей тестовой модели, потому что в противном случае Django создал бы таблицу с именем
tests_<model_name>, что может привести к конфликту с другими тестовыми моделями в другом приложении. Вот моя тестовая модель:class Recipe(models.Model): '''Test-only model to test out thumbnail registration.''' dish_image = models.ImageField(upload_to='recipes/') class Meta: db_table = 'files_tests_recipe'
цитирую связанный ответ:
Если вы хотите, чтобы модели определялись только для тестирования, то вы должны проверить билет Джанго 7835# в частности комментарий #24 часть из которых приводится ниже:
по-видимому, вы можете просто определить модели непосредственно в вашем tests.py. Syncdb никогда не импортирует tests.py, так что эти модели не будут синхронизированы с нормальная БД, но они будут синхронизированы с тестом базы данных, и может быть используется в тестах.
Я решение что я использую в моих проектах. Может быть, это кому-то помогает.
pip install django-fake-modelдва простых шага для создания поддельной модели:
1) Определите модель в любом файле (я обычно определяю модель в тестовом файле рядом с тестовым случаем)
from django_fake_model import models as f class MyFakeModel(f.FakeModel): name = models.CharField(max_length=100)2) Добавить декоратор
@MyFakeModel.fake_meна TestCase или для проверки функции.class MyTest(TestCase): @MyFakeModel.fake_me def test_create_model(self): MyFakeModel.objects.create(name='123') model = MyFakeModel.objects.get(name='123') self.assertEqual(model.name, '123')этот декоратор создает таблицу в вашей базе данных перед каждым тестом и удаляет таблицу после испытания.
и создать/удалить таблицы вручную:
MyFakeModel.create_table()/MyFakeModel.delete_table()
я придумал способ для тестовых моделей для django 1.7+.
основная идея заключается в том, чтобы сделать ваш
testsприложение, и добавить свойtestsдоINSTALLED_APPS.вот пример:
$ ls common __init__.py admin.py apps.py fixtures models.py pagination.py tests validators.py views.py $ ls common/tests __init__.py apps.py models.py serializers.py test_filter.py test_pagination.py test_validators.py views.pyа у меня по-другому
settingsдля различных целей (ref:разделение файла настроек), а именно:
settings/default.py: файл настройки базыsettings/production.py: для производстваsettings/development.py: для развитиеsettings/testing.py: для тестирования.и
settings/testing.py, вы можете изменитьINSTALLED_APPS:
settings/testing.py:from default import * DEBUG = True INSTALLED_APPS += ['common', 'common.tests']и убедитесь, что вы установили правильную метку для вашего приложения тестов, а именно,
common/tests/apps.pyfrom django.apps import AppConfig class CommonTestsConfig(AppConfig): name = 'common.tests' label = 'common_tests'
common/tests/__init__.py, настройка правильногоAppConfig(ref:Приложения Django).default_app_config = 'common.tests.apps.CommonTestsConfig'затем создайте миграцию БД с помощью
python manage.py makemigrations --settings=<your_project_name>.settings.testing testsнаконец, вы можете запустить свой тест с param
--settings=<your_project_name>.settings.testing.если вы используете py.тест, вы даже можете удалить вместе с .
py.test[pytest] DJANGO_SETTINGS_MODULE=kungfu.settings.testing
вот шаблон, который я использую для этого.
Я написал этот метод, который я использую на подклассе версии TestCase. Он выглядит следующим образом:
@classmethod def create_models_from_app(cls, app_name): """ Manually create Models (used only for testing) from the specified string app name. Models are loaded from the module "<app_name>.models" """ from django.db import connection, DatabaseError from django.db.models.loading import load_app app = load_app(app_name) from django.core.management import sql from django.core.management.color import no_style sql = sql.sql_create(app, no_style(), connection) cursor = connection.cursor() for statement in sql: try: cursor.execute(statement) except DatabaseError, excn: logger.debug(excn.message) passзатем я создаю специальный тест-специфичный models.py файл в чем-то вроде
myapp/tests/models.pyэто не входит в INSTALLED_APPS.в моем методе установки я вызываю create_models_from_app ('myapp.тесты"), и он создает соответствующие таблицы.
единственный "попался" с таким подходом является то, что вы не хочу создавать модели либо времени
setUpработает, поэтому я ловлю DatabaseError. Я думаю, что вызов этого метода может идти в верхней части тестового файла, и это будет работать немного лучше.
комбинируя ваши ответы, особенно @slacy'S, Я сделал это:
class TestCase(test.TestCase): initiated = False @classmethod def setUpClass(cls, *args, **kwargs): if not TestCase.initiated: TestCase.create_models_from_app('myapp.tests') TestCase.initiated = True super(TestCase, cls).setUpClass(*args, **kwargs) @classmethod def create_models_from_app(cls, app_name): """ Manually create Models (used only for testing) from the specified string app name. Models are loaded from the module "<app_name>.models" """ from django.db import connection, DatabaseError from django.db.models.loading import load_app app = load_app(app_name) from django.core.management import sql from django.core.management.color import no_style sql = sql.sql_create(app, no_style(), connection) cursor = connection.cursor() for statement in sql: try: cursor.execute(statement) except DatabaseError, excn: logger.debug(excn.message)при этом вы не пытаетесь создавать таблицы БД более одного раза, и вам не нужно менять свои INSTALLED_APPS.
если вы пишете многоразовое django-приложение,создайте минимальное тестовое приложение для него!
$ django-admin.py startproject test_myapp_project $ django-admin.py startapp test_myappдобавить
myappиtest_myappдоINSTALLED_APPS, создать свои модели там, и это хорошо, чтобы пойти!Я прошел через все эти ответы, а также Джанго билета 7835, и я, наконец, пошел на совершенно другой подход. Я хотел, чтобы мое приложение (каким-то образом расширяя queryset.значения () ), чтобы быть в состоянии быть проверены в изоляции; также, Мой пакет включает в себя некоторые модели, и я хотел четкое различие между тестовыми моделями и пакетами.
именно тогда я понял, что было проще добавить очень маленький проект django в пакет! Это также позволяет гораздо более чистое разделение кода IMHO:
там вы можете чисто и без какого-либо взлома определить свои модели, и вы знаете, что они будут созданы, когда вы запустите свои тесты оттуда!
если вы не пишете независимое, многоразовое приложение, которое вы можете все равно идите этим путем: создайте
test_myappприложение, и добавить его в свой INSTALLED_APPS только в отдельномsettings_test_myapp.py!
Comments