Подтвердить что ты не робот

Отсутствует таблица при запуске Django Unittest с Sqlite3

Я пытаюсь запустить unittest с Django 1.3. Обычно я использую MySQL как бэкэнд базы данных, но поскольку это очень медленно, чтобы развернуть для одного unittest, я использую Sqlite3.

Итак, чтобы переключиться на Sqlite3 только для моих unittests, в моих настройках .py у меня есть:

import sys
if 'test' in sys.argv:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME':'/tmp/database.db',
            'USER'       : '',
            'PASSWORD' : '',
            'HOST'     : '',
        }
    }

Когда я запускаю свой unittest с python manage.py test myapp.Test.test_myfunc, я получаю сообщение об ошибке:

DatabaseError: no such table: django_content_type

Google показывает, что несколько возможно для этого error, ни один из которых не применим ко мне. Я не запускаю Apache, поэтому я не вижу, как будут проблемы с правами доступа. Файл /tmp/database.db создается, поэтому /tmp доступен для записи. Приложение django.contrib.contenttypes включено в мой INSTALLED_APPS.

Что мне не хватает?

Изменить: я снова столкнулся с этой проблемой в Django 1.5, но ни одно из предлагаемых решений не работает.

4b9b3361

Ответ 1

В Django 1.4, 1.5, 1.6, 1.7 или 1.8 это должно быть достаточно, чтобы использовать:

if 'test' in sys.argv:
    DATABASES['default']['ENGINE'] = 'django.db.backends.sqlite3'

Не нужно переопределять TEST_NAME 1 или вызывать syncdb для запуска тестов. Как указывает @osa, по умолчанию с SQLite-движком необходимо создать тестовую базу данных в памяти (TEST_NAME=':memory:'). Вызов syncdb не должен быть необходимым, потому что тестовая среда Django сделает это автоматически с помощью вызова syncdb или migrate в зависимости от версии Django. 2 Вы можете наблюдать это с помощью manage.py test -v [2|3].

Очень плохо говоря, Django устанавливает тестовую среду:

  • Загрузка обычной базы данных NAME из settings.py
  • Обнаружение и конструирование ваших тестовых классов (__init__() вызывается)
  • Настройка базы данных NAME на значение TEST_NAME
  • Запуск тестов по базе данных NAME

Здесь rub: На шаге 2 NAME по-прежнему указывает вашу обычную (не тестирующую) базу данных. Если ваши тесты содержат запросы на уровне класса или запросы в __init__(), они будут выполняться против обычной базы данных, которая, скорее всего, не та, что вы ожидаете. Это указано в ошибке # 21143.

Не выполнять:

class BadFooTests(TestCase):
    Foo.objects.all().delete()     # <-- class level queries, and

    def __init__(self):
        f = Foo.objects.create()   # <-- queries in constructor
        f.save()                   #     will run against the production DB

    def test_foo(self):
        # assert stuff

поскольку они будут выполняться против базы данных, указанной в NAME. Если на этом этапе NAME указывает на действительную базу данных (например, вашу производственную базу данных), запрос будет запущен, но может иметь непреднамеренные последствия. Если вы переопределили ENGINE и/или NAME, чтобы он не указывал на ранее существовавшую базу данных, генерируется исключение, потому что тестовая база данных еще не создана:

django.db.utils.DatabaseError: no such table: yourapp_foo  # Django 1.4
DatabaseError: no such table: yourapp_foo                  # Django 1.5
OperationalError: no such table: yourapp_foo               # Django 1.6+

Вместо этого выполните:

class GoodFooTests(TestCase):

    def setUp(self):
        f = Foo.objects.create()   # <-- will run against the test DB
        f.save()                   #

    def test_foo(self):
        # assert stuff

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


[1] В Django >= 1.7, DATABASES[alias]['TEST_NAME'] устарел в пользу DATABASES[alias]['TEST']['NAME']
[2] См. Метод create_test_db() в db/backends/creation.py

Ответ 2

У меня тоже была эта проблема. Оказалось, что мне нужно добавить свойство TEST_NAME в файл settings.py, чтобы правильно определить тестовую базу данных. Он решил проблему для меня:

if 'test' in sys.argv:
    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'),
       }
    }

Ответ 3

Просто добавьте еще один случай:

Если вы пытаетесь выполнить обновление до 1,8 от 1,6 (или от установки без переноса до установки миграции), вы можете нажать эту ошибку, если не выполняете созданные миграции.

У меня была такая же проблема, и мне пришлось создавать миграции, чтобы тестовый бегун мог их использовать, что не было интуитивным, поскольку предварительные миграции, тесты просто создавали бы новую БД на основе выполнения syncdb, который всегда работал.

Ответ 4

Для справки в будущем это также происходит, если ваше приложение не добавлено в ваш INSTALLED_APPS, например:

INSTALLED_APPS = (
   ...
   'myapp'
)

В противном случае вы получите:

OperationalError: no such table: myapp_mytable

Ответ 5

Пробовав все вышеизложенное, я обнаружил еще одну причину: -

Если какая-либо из ваших моделей не создана одной из ваших миграций.

Я сделал некоторую отладку, и кажется, что тестирование Django настраивает базу данных, применяя все ваши миграции в порядке, начиная с 001_initial.py, прежде чем пытаться SELECT из таблиц на основе ваших models.py

В моем случае таблица каким-то образом не была добавлена ​​в миграции, но добавлена ​​вручную, поэтому полный набор перенастройки не может быть правильно применен. Когда я вручную исправил миграцию 001_initial.py, чтобы создать эту таблицу, OperationalError ушел.

Ответ 6

Ваша база данных, вероятно, пуста, она должна быть настроена со всеми таблицами, соответствующими вашим моделям. Обычно это делается при запуске python manage.py syncdb во-первых, для создания всех ваших таблиц базы данных. Проблема в том, что в вашем случае, когда вы запускаете syncdb, python не увидит, что вы запускаете тест, чтобы вместо этого попытаться настроить таблицы в базе данных MySQL.

Чтобы обойти это, временно измените

if 'test' in sys.argv:

к

if True:

Затем запустите python manage.py syncdb, чтобы настроить таблицы базы данных sqlite. Теперь, когда все настроено, вы можете вернуться в if 'test'..., и все должно работать плавно. Однако вы, вероятно, захотите перенести свою базу данных из каталога /tmp: django необходимо повторно использовать одну и ту же базу данных каждый раз, когда вы запускаете свои тесты, в противном случае вам придется создавать таблицы базы данных перед каждым тестом.

Обратите внимание: если вы добавите новые модели, вам нужно будет повторить эту процедуру для создания новых таблиц в sqlite. Если вы добавите новые поля в существующую модель, вам нужно будет вручную добавить столбцы в вашу базу данных sqlite с помощью интерфейса sqlite и ALTER TABLE... или сделать это автоматически с помощью инструмента, такого как South.

Ответ 7

Мне пришлось добавить следующие строки после определения тестовой базы данных:

from django.core.management import call_command
call_command('syncdb', migrate=True)

Ответ 8

Для тех, кто пробовал все возможные способы, но все еще застрял в этом:

Поскольку наш тестовый код все еще работает на другой машине, но не мой, я попытался:

  • Создайте новый виртуальный env. (так что изолируйте влияние приложений)
  • Клонировать новый репозиторий. (изолировать влияние игнорируемых файлов)
  • Установить settings в sqlite3 вместо psql (изолировать влияние базы данных и параметров базы данных)
  • Проверьте переменные env и .env файл (так как я использовал foreman)

Никто из них не помог. Пока я:

  • Создайте новую учетную запись на моей машине. (Итак, начните чистку)
  • Клонировать хранилище.
  • Запуск тестов → Успех 😑
  • Вернитесь к моей основной учетной записи.
  • Откройте новый терминал (kill current tmux server, если вы их используете).
  • Запуск тестов → Успех 😯

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

Ответ 9

Для тех, кто придет сюда, ищет, почему Django продолжает создавать базу данных, независимо от опции --keepdb. Почему он говорит Using existing test database for alias 'default', но затем запускает кучу операторов CREATE TABLE.

Если вы не установите параметр DATABASES > default > TEST > NAME, Django попытается использовать в базе данных памяти, и это не будет быть сохранен, поэтому установите это и переопределите значения по умолчанию.

Вы можете сделать это следующим образом:

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(ROOT_DIR, 'data', 'db.dev.sqlite3'), 'TEST': { 'NAME': os.path.join(ROOT_DIR, 'data', 'db.test.sqlite3'), } } }