I have a model with managed = False.
class SampleModel(models.Model):
apple = models.CharField(max_length=30)
orange = models.CharField(max_length=3
You can use SchemaEditor in TestCase.setUp method to explicitly create models with 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'
And in your tests:
# 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())
Execute raw SQL to create the table in the test setup:
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 ...")
Simply move your unmanaged models to a dedicated app and delete migrations folder. Details in my answer in Multi db and unmanged models - Test case are failing
Using pytest and pytest-django
To make this work (has been tested with django 3.0.2, pytest 5.3.5 and pytest-django 3.8.0):
--no-migrations
.django_db_setup
. The issue of not being able to call pytest fixtures directly is discussed here: https://github.com/pytest-dev/pytest/issues/3950conftest.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)
Create your own test runner using this:
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
Then on your settings add this class to TEST_RUNNER.
Nice plug and play solution. Just paste this before your test class definition. (note: django 1.8 used)
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()