Fehlende Tabelle beim Ausführen von Django Unittest mit Sqlite3

Ich versuche, einen Unbekannten mit Django 1.3 zu laufen. Normalerweise verwende ich MySQL als meine Datenbank-Backend, aber da dies schmerzhaft langsam zu spinup für eine einzige unittest ist, benutze ich Sqlite3.

Also, um zu Sqlite3 nur für meine unittests zu wechseln, in meinem settings.py ich habe:

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

Wenn ich meine unbescheidenen mit python manage.py test myapp.Test.test_myfunc , bekomme ich die python manage.py test myapp.Test.test_myfunc :

 DatabaseError: no such table: django_content_type 

Googeln zeigt, dass es einige mögliche Gründe für diesen Fehler gibt , von denen keiner für mich anwendbar erscheint. Ich laufe nicht Apache, also sehe ich nicht, wie Berechtigungen ein Problem sein würden. Die Datei /tmp/database.db wird erstellt, also ist / tmp beschreibbar. Die app django.contrib.contenttypes ist in meinem INSTALLED_APPS enthalten.

Was vermisse ich?

Bearbeiten: Ich habe in diesem Problem wieder in Django 1.5, aber keine der vorgeschlagenen Lösungen funktionieren.

9 Solutions collect form web for “Fehlende Tabelle beim Ausführen von Django Unittest mit Sqlite3”

In Django 1.4, 1.5, 1.6, 1.7 oder 1.8 sollte es ausreichen, um zu verwenden:

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

Es sollte nicht nötig sein, TEST_NAME 1 zu überschreiben, noch syncdb , um Tests auszuführen. Wie @osa darauf hinweist, ist die Voreinstellung mit der SQLite-Engine, die Testdatenbank im Speicher zu erstellen ( TEST_NAME=':memory:' ). Das Aufrufen von syncdb sollte nicht notwendig sein, da das Test-Framework von Django dies automatisch über einen Aufruf von syncdb oder migrate Abhängigkeit von der Django-Version durchführt. 2 Sie können dies mit manage.py test -v [2|3] .

Sehr lose spricht Django die Testumgebung durch:

  1. Laden Sie die reguläre Datenbank NAME aus Ihren settings.py
  2. Entdecken und Konstruieren deiner __init__() ( __init__() heißt)
  3. Setzen der Datenbank NAME auf den Wert von TEST_NAME
  4. Ausführen der Tests gegen die Datenbank NAME

Hier ist die Rub: In Schritt 2 zeigt NAME immer noch auf Ihre regelmäßige (Non-Test) Datenbank. Wenn Ihre Tests Klassen-Level-Abfragen oder Abfragen in __init__() , werden sie gegen die reguläre Datenbank ausgeführt, die wahrscheinlich nicht das ist, was Sie erwarten. Dies wird im Fehler # 21143 identifiziert.

Nicht tun:

 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 

Da diese gegen die in NAME angegebene Datenbank ausgeführt werden. Wenn NAME in diesem Stadium auf eine gültige Datenbank (zB Ihre Produktionsdatenbank) verweist, wird die Abfrage ausgeführt, kann aber unbeabsichtigte Konsequenzen haben. Wenn Sie ENGINE und / oder NAME so überschrieben haben, dass sie nicht auf eine bereits vorhandene Datenbank verweisen, wird eine Ausnahme ausgelöst, da die Testdatenbank noch nicht erstellt werden muss:

 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+ 

Stattdessen:

 class GoodFooTests(TestCase): def setUp(self): f = Foo.objects.create() # <-- will run against the test DB f.save() # def test_foo(self): # assert stuff 

Also, wenn Sie Fehler sehen, überprüfen Sie, um zu sehen, dass Ihre Tests keine Abfragen enthalten, die die Datenbank außerhalb Ihrer Testklassenmethodendefinitionen treffen könnten.


[1] In Django> = 1.7 wird DATABASES[alias]['TEST_NAME'] zugunsten von DATABASES[alias]['TEST']['NAME'] veraltet
[2] Siehe die Methode create_test_db() in db/backends/creation.py

Ich hatte auch dieses Problem. Stellte sich heraus, dass ich eine TEST_NAME-Eigenschaft in der Datei settings.py hinzufügen musste, um die Testdatenbank korrekt zu identifizieren. Es hat mir das Problem gelöst:

 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'), } } 

Nur um einen weiteren Fall hinzuzufügen:

Wenn Sie versuchen, auf 1.8 von 1.6 (oder von einem Nicht-Migrations-Setup zu einem Migrations-Setup) zu aktualisieren, können Sie diesen Fehler treffen, wenn Sie keine geschalteten Migrationen ausgeführt haben.

Ich hatte das gleiche Problem und musste Migrationen erstellen, damit der Test-Läufer sie nutzen konnte, was nicht intuitiv war, weil Vormigrationen, die Tests nur eine neue DB auf der Grundlage von syncdb, die immer funktionierte.

Ihre Datenbank ist wahrscheinlich leer, es muss mit allen Tabellen entsprechend Ihren Modellen eingerichtet werden. Normalerweise würde dies geschehen, indem man python manage.py syncdb zuerst, um alle Ihre Datenbanktabellen zu erstellen. Das Problem ist, dass in Ihrem Fall, wenn Sie Syncdb ausführen, wird Python nicht sehen, dass Sie einen Test laufen, so wird es versuchen, die Einrichtung von Tabellen in Ihrer MySQL-Datenbank statt.

Um dies zu umgehen, ändern Sie sich vorübergehend

 if 'test' in sys.argv: 

nach

 if True: 

Dann laufe python manage.py syncdb um die sqlite Datenbanktabellen python manage.py syncdb . Jetzt, da alles eingerichtet ist, kannst du dich zurücksetzen, if 'test'... und alles sollte reibungslos laufen. Allerdings möchten Sie wahrscheinlich Ihre Datenbank aus dem Verzeichnis /tmp : django muss bei jedem Test die gleiche Datenbank verwenden, sonst müssen Sie vor jedem Test Datenbanktabellen erstellen.

Beachten Sie, dass, wenn Sie neue Modelle hinzufügen, müssen Sie diese Prozedur wiederholen, um die neuen Tabellen in sqlite zu erstellen. Wenn Sie einem vorhandenen Modell neue Felder hinzufügen, müssen Sie Ihrer sqlite-Datenbank mit der sqlite-Schnittstelle und ALTER TABLE... die Spalten manuell hinzufügen, oder machen Sie es automatisch mit einem Tool wie South.

Für zukünftige Referenz ist dies auch passiert, wenn Ihre Anwendung nicht zu Ihrem INSTALLED_APPS hinzugefügt INSTALLED_APPS , zum Beispiel:

 INSTALLED_APPS = ( ... 'myapp' ) 

Sonst bekommst du;

 OperationalError: no such table: myapp_mytable 

Nachdem ich all das oben versucht habe, entdeckte ich schließlich einen anderen Grund, das passieren kann: –

Wenn eines Ihrer Modelle nicht von einer Ihrer Migrationen erstellt wird.

Ich habe einige Debugging und es scheint, dass Django-Tests richtet die Datenbank, indem Sie alle Ihre Migrationen in Reihenfolge, beginnend mit 001_initial.py , bevor Sie versuchen, SELECT aus den Tabellen auf der Grundlage Ihrer models.py

In meinem Fall war ein Tisch irgendwie nicht zu den Migrationen hinzugefügt worden, aber manuell hinzugefügt, so dass die volle Migrationssatz nicht richtig angewendet werden konnte. Als ich die 001_initial.py Migration manuell behoben habe , um diese Tabelle zu erstellen, ging der OperationalError weg.

Ich musste die folgenden Zeilen nach der Definition der Testdatenbank hinzufügen:

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

Für diejenigen, die alle möglichen Möglichkeiten ausprobiert haben, aber immer noch in diesem stecken:

Da unser Testcode immer noch in einer anderen Maschine läuft, aber nicht von mir, habe ich versucht:

  • Erstellen Sie eine neue virtuelle env. (So ​​isolieren die Auswirkungen von apps)
  • Klone ein neues Repository. (Isoliere den Einfluss von ignorierten Dateien)
  • Setzen Sie in den settings , um sqlite3 anstelle von psql (isolieren Sie den Einfluss der Datenbank und die Datenbankeinstellungen)
  • Check env Variablen und .env Datei (seit ich foreman )

Keiner von denen half. Bis ich:

  1. Erstellen Sie ein neues Konto auf meiner Maschine. (So ​​beginnen Sie sauber)
  2. Klone das Repository.
  3. Führen Sie Tests -> Erfolg 😑
  4. Gehen Sie zurück zu meinem Hauptkonto.
  5. Öffnen Sie ein neues Terminal (töten Sie den aktuellen tmux Server, wenn Sie sie verwenden).
  6. Führen Sie Tests -> Erfolg 😯

Also das ist keine echte Antwort für deine Frage, da ich nicht weiß was falsch war und wie es behoben ist, nur ein weiterer Vorschlag, den du probierst.

Für alle, die hierher kommen, auf der Suche nach warum Django hält die Schaffung einer Datenbank unabhängig von der --keepdb Option. Warum heißt es, die Using existing test database for alias 'default' , aber dann läuft eine Reihe von CREATE TABLE Anweisungen.

Wenn Sie keine DATABASES> default> TEST> NAME- Einstellung festlegen, wird Django versuchen, in der Speicherdatenbank zu verwenden, und es wird nicht beibehalten, also stellen Sie dies ein und überschreiben Sie die Standardwerte .

Du kannst es so machen:

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'), } } }

  • Wickeln Sie einen offenen Stream mit io.TextIOWrapper
  • Warum verspottet man die Instanz / das Objekt, das an eine verspottete Methode übergeben wird, wenn es aufgerufen wird?
  • Wie teste ich eine Celery-Aufgabe?
  • Wie bekomme ich Unbekannte TestCases
  • AssertRaises in python unit-test nicht fangen die Ausnahme
  • Persist Variable Änderungen zwischen Tests in unittest?
  • Beschleunigung der Django-Prüfung
  • Django-pytest setup_method Datenbankproblem
  • Erstellen und importieren Sie Helper-Funktionen in Tests, ohne Pakete im Testverzeichnis mit py.test zu erstellen
  • Tornado-Unit-Test mit Web-Sockets - was ist mit Stack-Kontext?
  • Cython & Python Project Test Driven Entwicklung und .pyx Datei Struktur Beratung
  • Python ist die beste Programmiersprache der Welt.