Запуск юнит-тестов Django приводит к тому, что миграции South дублируют таблицы.

Как запретить юнит-тестам Django запускать южные миграции?

У меня есть пользовательское приложение Django, myapp, которое я пытаюсь протестировать с помощью manage.py test myapp, но когда я запускаю его, я получаю сообщение об ошибке:

django.db.utils.OperationalError: table "myapp_mymodel" already exists

и, конечно же, трассировка показывает, что выполняется South:

File "/usr/local/myproject/.env/local/lib/python2.7/site-packages/south/management/commands/test.py", line 8, in handle
super(Command, self).handle(*args, **kwargs)

Однако в моих настройках я указал:

SOUTH_TESTS_MIGRATE = 0
SKIP_SOUTH_TESTS = 1

который, я считаю, должен помешать тестовой среде Django выполнять какие-либо южные компоненты.

Что я делаю неправильно?

Изменить: я обошел это, просто удалив юг с помощью:

if 'test' in sys.argv:
    INSTALLED_APPS.remove('south')

Однако затем я получил:

ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the NAME value.

Для моих тестовых настроек базы данных я использовал:

DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3'
    }
}

который отлично работал в Django 1.4. Теперь я использую Django 1.5, и я думаю, что это не кошерно. Однако я не вижу значения NAME, чтобы это исправить. Все они сообщают, что ни одна из моих таблиц не существует. Я пробовал:

DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/dev/shm/test.db',
        'TEST_NAME': '/dev/shm/test.db',
    }
}


DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',
        'TEST_NAME': ':memory:',
    }
}

DATABASES = {
    'default':{
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
        'TEST_NAME': os.path.join(os.path.dirname(__file__), 'test.db'),
    }
}

кажется, что каждый создает физический файл test.db, чего я не понимаю, потому что юнит-тесты должны запускаться в памяти. Он никогда не должен ничего сохранять на диск. Предположительно, он не может запустить syncdb после создания файла, но до того, как он выполнит фактический модульный тест. Как я могу это исправить?

Редактировать: я обнаружил, что в одной из моих форм я заполнял варианты полей, напрямую запрашивая модель (тогда как я должен был делать это внутри формы init), поэтому, когда тестовая среда Django импортировала мой модели он пытался прочитать таблицу до того, как была создана база данных sqlite3. Я исправил это, но теперь я получаю сообщение об ошибке:

DatabaseError: table "myapp_mythroughmodel" already exists

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

Редактировать: у меня была определена дублирующая модель, из-за чего Django пытался создать ее дважды, что привело к ошибке.


person Cerin    schedule 01.05.2014    source источник
comment
Попробуйте использовать явные логические значения: SOUTH_TESTS_MIGRATE = False и SKIP_SOUTH_TESTS = True   -  person Steve Jalim    schedule 01.05.2014
comment
@stevejalim, без изменений...   -  person Cerin    schedule 01.05.2014


Ответы (2)


Это также случилось со мной с устаревшим кодом, но по другой причине.

У меня было две модели с db_table, ссылающимися на одну и ту же таблицу db. Я знаю, что это глупо, но это не моя вина )

И я никогда не нашел в Интернете ничего, что могло бы мне помочь. Меня спасло многословие, установленное на 3 (manage.py test -v 3). Надеюсь, это кому-нибудь поможет.

class Bla1(Model):
    some_column = ...
    class Meta:
        db_table = 'some_table'

class Bla2(Model):
    some_column = ...
    class Meta:
        db_table = 'some_table'
person Dmitriy Kuznetsov    schedule 15.08.2014

Эта ошибка была результатом нескольких проблем. Я суммирую их здесь, чтобы помочь другим, кто, возможно, наткнулся на это.

  1. Убедитесь, что ваши настройки settings.DATABASES установлены правильно. В документах Django упоминается использование TEST_NAME, но для ясности мне проще проверить команду test и переопределить все. например внизу моего settings.py у меня есть:

    if 'test' in sys.argv:
        DATABASES = {
            'default':{
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': ':memory:',
            },
        }
    

    Если у вас нет веских причин, всегда используйте :memory:, чтобы убедиться, что он работает в памяти и не создает физический файл, который застрянет на диске. По какой-то странной причине многие другие ответы на SO рекомендуют указывать буквальный путь к файлу test.db для тестирования. Это ужасный совет.

  2. Если вы не хотите тестировать Юг и/или свои Южные миграции, отключите Юг, потому что это только усложнит ситуацию:

    SOUTH_TESTS_MIGRATE = False
    SKIP_SOUTH_TESTS = True
    
  3. Не будьте тупыми, как я, и не пытайтесь получить доступ к своим моделям до того, как они будут созданы. В основном это означает, что нельзя напрямую ссылаться на модели из полей других моделей или форм. например

    class MyForm(forms.Form):
    
        somefield = forms.ChoiceField(
            required=True,
            choices=[(_.id, _.name) for _ in OtherModel.objects.filter(criteria=blah)],
        )
    

    Это может работать в коде, где ваша база данных уже существует, но это сломает инфраструктуру юнит-тестов Django, когда он попытается загрузить ваши тесты, которые загружают ваши models.py и forms.py, заставляя его читать несуществующую таблицу. Вместо этого установите значение выбора в __init__() формы.

person Cerin    schedule 01.05.2014