Как создать таблицу во время тестов Django с managed = False - PullRequest
31 голосов
/ 11 августа 2011

У меня есть модель с управлением = Ложь.

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 - https://docs.djangoproject.com/en/dev/ref/models/options/#managed документирует следующее:

Для тестов, включающих модели с управляемым = False, вы должны убедиться, что в рамках настройки теста созданы правильные таблицы.

Как я могу на самом деле«создать» таблицы во время настройки теста?Или, как альтернатива, как я могу сделать так, чтобы, когда я запускаю тесты, эта модель имела значение «managed = True» на время теста?

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

Ответы [ 7 ]

14 голосов
/ 12 августа 2011

Ознакомьтесь с этим сообщением в блоге: 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
4 голосов
/ 11 августа 2011

Выполните необработанный 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 ...")
3 голосов
/ 12 августа 2011

Создайте свой собственный тестовый прогон, используя это:

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.

2 голосов
/ 12 апреля 2018

Вы можете использовать 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())
2 голосов
/ 07 ноября 2016

Просто добавьте: 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 

Обратите внимание, что вам также необходимо позаботиться о миграции (см. Тестирование приложения django с несколькими устаревшими базами данных )

MIGRATION_MODULES = {
    'news': 'news.test_migrations',
    'economist': 'economist.test_migrations'
}
2 голосов
/ 19 июля 2016

Отличное решение «включай и работай».Просто вставьте это перед определением вашего тестового класса.(примечание: используется 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()
2 голосов
/ 07 июля 2015

Быстрое исправление, если у вас не так много неуправляемых таблиц:

Сначала добавьте новую переменную в настройки.

# 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...