Отсутствует таблица при запуске Django Unittest с Sqlite3 - PullRequest
19 голосов
/ 07 сентября 2011

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

Таким образом, чтобы переключиться на Sqlite3 только для моих юнит-тестов, в моих settings.py у меня есть:

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

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

DatabaseError: no such table: django_content_type

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

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

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

Ответы [ 11 ]

12 голосов
/ 25 ноября 2014

В 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 настраивает тестовую среду:

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

Вот в чем проблема: На шаге 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

4 голосов
/ 31 августа 2016

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

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

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

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

4 голосов
/ 30 декабря 2015

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

Если вы пытаетесь обновить версию 1.8 с 1.6 (или с установки без миграции на установку миграции), вы можете столкнуться с этой ошибкой, если у вас нет 'не запускать созданные миграции.

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

4 голосов
/ 23 марта 2013

У меня тоже была эта проблема. Оказалось, что мне пришлось добавить свойство 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 голосов
/ 21 августа 2014

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

INSTALLED_APPS = (
   ...
   'myapp'
)

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

OperationalError: no such table: myapp_mytable
1 голос
/ 07 сентября 2011

Ваша база данных, вероятно, пуста, она должна быть настроена со всеми таблицами, соответствующими вашим моделям. Обычно это можно сделать, выполнив сначала 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..., или сделать это автоматически, используя такой инструмент, как Юг.

0 голосов
/ 06 октября 2018

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

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

Например,

0001_accounts.py {create the model User}
0002_accounts.py {{for user in User.objects.all(): user.save() }
0003_accounts.py {add a new column to User object}

Сбой 000 000 при попытке сохранить объект пользователя, но нового столбца пока нет.

Для отладки:

switch to an empty database
run python manage.py migrate

Посмотрите, где это останавливается, это, вероятно, хакерская миграция данных, которую вы хотите раскомментировать.

0 голосов
/ 19 марта 2018

У меня была похожая проблема, и я был вызван предыдущим кодом ветки, поэтому я исправил ее, удалив файлы pyc в моих проектах:

find -regex .*pyc | xargs sudo rm
0 голосов
/ 09 сентября 2016

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

Если вы не установили параметр БАЗЫ ДАННЫХ> 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'), } } }

0 голосов
/ 29 июня 2015

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

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

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

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

  1. Создаю новую учетную запись на моей машине.(Так что начните с чистого листа)
  2. Клонируйте репозиторий.
  3. Запустите тесты -> Успех ?
  4. Вернитесь к моей основной учетной записи.
  5. Откройте новый терминал(убейте текущий tmux сервер, если вы их используете).
  6. Запустите тесты -> Успех ?

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

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