我有一个托管= False的模型。
class SampleModel(models.Model):
apple = models.CharField(max_length=30)
orange = models.CharField(max_length=30)
class Meta:
managed = False
我有一个单元测试,它创建了一个SampleModel,但是当我运行测试时,我得到了:
DatabaseError: no such table: SAMPLE_SAMPLE_MODEL
django docs - https://docs.djangoproject.com/en/dev/ref/models/options/#managed记录了以下内容:
对于涉及托管= False的模型的测试,由您决定 确保在测试设置中创建正确的表格。
如何在测试设置期间实际“创建”表格?或者,我怎样才能使它在运行测试时,在测试期间该模型具有“managed = True”?
在实际应用程序中,此模型实际上由数据库中的视图支持。但是对于测试期间,我想将其视为一个表,并能够在那里插入测试数据。
答案 0 :(得分:14)
查看此博文:http://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/它详细描述了为非托管模型创建测试运行器。
from django.test.simple import DjangoTestSuiteRunner
class ManagedModelTestRunner(DjangoTestSuiteRunner):
"""
Test runner that automatically makes all unmanaged models in your Django
project managed for the duration of the test run, so that one doesn't need
to execute the SQL manually to create them.
"""
def setup_test_environment(self, *args, **kwargs):
from django.db.models.loading import get_models
self.unmanaged_models = [m for m in get_models()
if not m._meta.managed]
for m in self.unmanaged_models:
m._meta.managed = True
super(ManagedModelTestRunner, self).setup_test_environment(*args,
**kwargs)
def teardown_test_environment(self, *args, **kwargs):
super(ManagedModelTestRunner, self).teardown_test_environment(*args,
**kwargs)
# reset unmanaged models
for m in self.unmanaged_models:
m._meta.managed = False
答案 1 :(得分:4)
执行原始SQL以在测试设置中创建表:
from django.db import connection
class MyTest(unittest.TestCase):
def setUp(self):
connection.cursor().execute("CREATE TABLE ...")
def tearDown(self):
connection.cursor().execute("DROP TABLE ...")
答案 2 :(得分:3)
使用以下方法创建自己的测试运行器:
from django.test.simple import DjangoTestSuiteRunner
class NoDbTestRunner(DjangoTestSuiteRunner):
""" A test runner to test without database creation """
def setup_databases(self, **kwargs):
""" Override the database creation defined in parent class """
#set manage=True for that specific database on here
然后在您的设置上将此类添加到TEST_RUNNER。
答案 3 :(得分:2)
如果您没有许多非托管表,请快速解决问题:
首先在设置中添加一个新变量。
# settings.py
import sys
UNDER_TEST = (len(sys.argv) > 1 and sys.argv[1] == 'test')
然后在模型中
# models.py
from django.conf import settings
class SampleModel(models.Model):
apple = models.CharField(max_length=30)
orange = models.CharField(max_length=30)
class Meta:
managed = getattr(settings, 'UNDER_TEST', False)
答案 4 :(得分:2)
不错的即插即用解决方案。只需在测试类定义之前粘贴它即可。 (注意:使用django 1.8)
from django.db.models.loading import get_models
def change_managed_settings_just_for_tests():
"""django model managed bit needs to be switched for tests."""
unmanaged_models = [m for m in get_models() if not m._meta.managed]
for m in unmanaged_models:
m._meta.managed = True
change_managed_settings_just_for_tests()
答案 5 :(得分:2)
添加:django.db.models.loading.get_models将在Django 1.9中删除(参见https://github.com/BertrandBordage/django-cachalot/issues/33)。
以下是Django 1.10的更新版本:
class UnManagedModelTestRunner(DiscoverRunner):
'''
Test runner that automatically makes all unmanaged models in your Django
project managed for the duration of the test run.
Many thanks to the Caktus Group
'''
def setup_test_environment(self, *args, **kwargs):
from django.apps import apps
self.unmanaged_models = [m for m in apps.get_models() if not m._meta.managed]
for m in self.unmanaged_models:
m._meta.managed = True
super(UnManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)
def teardown_test_environment(self, *args, **kwargs):
super(UnManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs)
# reset unmanaged models
for m in self.unmanaged_models:
m._meta.managed = False
请注意,您还需要注意迁移(请参阅Testing django application with several legacy databases)
MIGRATION_MODULES = {
'news': 'news.test_migrations',
'economist': 'economist.test_migrations'
}
答案 6 :(得分:2)
您可以SchemaEditor方法中的TestCase.setUp
使用managed = False
明确创建模型。
# models.py
from django.db import models
class Unmanaged(models.Model):
foo = models.TextField()
class Meta:
# This model is not managed by Django
managed = False
db_table = 'unmanaged_table'
在你的测试中:
# tests.py
from django.db import connection
from django.test import TestCase
from myapp.models import Unmanaged
class ModelsTestCase(TestCase):
def setUp(self):
super().setUp()
with connection.schema_editor() as schema_editor:
schema_editor.create_model(Unmanaged)
if Unmanaged._meta.db_table not in connection.introspection.table_names():
raise ValueError("Table `{table_name}` is missing in test database.".format(table_name=Unmanaged._meta.db_table))
def tearDown(self):
super().tearDown()
with connection.schema_editor() as schema_editor:
schema_editor.delete_model(Unmanaged)
def test_unmanaged_model(self):
with self.assertNumQueries(num=3):
self.assertEqual(0, Unmanaged.objects.all().count())
Unmanaged.objects.create()
self.assertEqual(1, Unmanaged.objects.all().count())
答案 7 :(得分:0)
只需将非托管模型移动到专用应用程序并删除迁移文件夹。 Multi db and unmanged models - Test case are failing
中我的答案的详细信息答案 8 :(得分:0)
使用pytest和pytest-django
要使其正常工作(已通过 django 3.0.2 , pytest 5.3.5 和 pytest-django 3.8.0 进行了测试) :
--no-migrations
运行pytest。django_db_setup
。这里讨论了无法直接调用pytest固定装置的问题:https://github.com/pytest-dev/pytest/issues/3950 conftest.py
# example file
import pytest
from pytest_django.fixtures import _disable_native_migrations
@pytest.fixture(scope="session")
def django_db_setup(
request,
django_test_environment,
django_db_blocker,
django_db_use_migrations,
django_db_keepdb,
django_db_createdb,
django_db_modify_db_settings,
):
# make unmanaged models managed
from django.apps import apps
unmanaged_models = []
for app in apps.get_app_configs():
unmanaged_models = [m for m in app.get_models()
if not m._meta.managed]
for m in unmanaged_models:
m._meta.managed = True
# copypasta fixture code
"""Top level fixture to ensure test databases are available"""
from pytest_django.compat import setup_databases, teardown_databases
setup_databases_args = {}
if not django_db_use_migrations:
_disable_native_migrations()
if django_db_keepdb and not django_db_createdb:
setup_databases_args["keepdb"] = True
with django_db_blocker.unblock():
db_cfg = setup_databases(
verbosity=request.config.option.verbose,
interactive=False,
**setup_databases_args
)
def teardown_database():
with django_db_blocker.unblock():
try:
teardown_databases(db_cfg, verbosity=request.config.option.verbose)
except Exception as exc:
request.node.warn(
pytest.PytestWarning(
"Error when trying to teardown test databases: %r" % exc
)
)
if not django_db_keepdb:
request.addfinalizer(teardown_database)