135 Stimmen

Wie kann man die Testdatenbank von Django nur im Speicher ausführen?

Meine Django-Unit-Tests benötigen viel Zeit zum Ausführen, also suche ich nach Möglichkeiten, das zu beschleunigen. Ich erwäge die Installation eines SSD aber ich weiß, dass das auch seine Nachteile hat. Natürlich gibt es Dinge, die ich mit meinem Code machen könnte, aber ich suche nach einer strukturellen Lösung. Selbst das Ausführen eines einzelnen Tests ist langsam, da die Datenbank jedes Mal neu erstellt/nach Süden migriert werden muss. Also hier ist meine Idee...

Da ich weiß, dass die Testdatenbank immer recht klein sein wird, warum kann ich das System nicht einfach so konfigurieren, dass immer die gesamte Testdatenbank im RAM gehalten wird? Die Festplatte wird überhaupt nicht berührt. Wie kann ich das in Django konfigurieren? Ich würde es vorziehen, weiterhin mit MySQL da ich das in der Produktion verwende, aber wenn SQLite 3 oder etwas anderes macht dies einfach, ich würde diesen Weg gehen.

Verfügen SQLite oder MySQL über eine Option zur vollständigen Ausführung im Speicher? Es sollte möglich sein, eine RAM-Disk zu konfigurieren und dann die Testdatenbank so zu konfigurieren, dass sie ihre Daten dort speichert, aber ich bin mir nicht sicher, wie ich Django/MySQL anweisen kann, ein anderes Datenverzeichnis für eine bestimmte Datenbank zu verwenden, zumal es bei jedem Lauf gelöscht und neu erstellt wird. (Ich bin auf einem Mac FWIW.)

177voto

Etienne Punkte 11992

Wenn Sie Ihre Datenbank-Engine auf sqlite3 einstellen, wenn Sie Ihre Tests durchführen, Django wird eine In-Memory-Datenbank verwenden .

Ich verwende diesen Code in meinem settings.py um die Engine auf sqlite zu setzen, wenn ich meine Tests ausführe:

if 'test' in sys.argv:
    DATABASE_ENGINE = 'sqlite3'

Oder in Django 1.2:

if 'test' in sys.argv:
    DATABASES['default'] = {'ENGINE': 'sqlite3'}

Und schließlich in Django 1.3 und 1.4:

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

(Der vollständige Pfad zum Backend ist bei Django 1.3 nicht unbedingt notwendig, macht die Einstellung aber vorwärtskompatibel).

Sie können auch die folgende Zeile hinzufügen, falls Sie Probleme mit Süd-Migrationen haben:

    SOUTH_TESTS_MIGRATE = False

86voto

Anurag Uniyal Punkte 81337

Normalerweise erstelle ich eine separate Einstellungsdatei für Tests und verwende sie im Testbefehl, z. B.

python manage.py test --settings=mysite.test_settings myapp

Sie hat zwei Vorteile:

  1. Sie brauchen nicht zu prüfen, ob test oder ein anderes magisches Wort in sys.argv, test_settings.py kann einfach sein

    from settings import *
    
    # make tests faster
    SOUTH_TESTS_MIGRATE = False
    DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}

    Sie können sie auch weiter an Ihre Bedürfnisse anpassen und die Testeinstellungen sauber von den Produktionseinstellungen trennen.

  2. Ein weiterer Vorteil ist, dass Sie Tests mit der Produktionsdatenbank-Engine anstelle von sqlite3 durchführen können, um subtile Fehler zu vermeiden, also verwenden Sie beim Entwickeln

    python manage.py test --settings=mysite.test_settings myapp

    und vor der Übergabe des Codes einmal ausführen

    python manage.py test myapp

    nur um sicher zu sein, dass alle Tests wirklich bestanden werden.

21voto

muudscope Punkte 6362

MySQL unterstützt eine Speicher-Engine namens "MEMORY", die Sie in Ihrer Datenbankkonfiguration konfigurieren können ( settings.py ) als solche:

    'USER': 'root',                      # Not used with sqlite3.
    'PASSWORD': '',                  # Not used with sqlite3.
    'OPTIONS': {
        "init_command": "SET storage_engine=MEMORY",
    }

Beachten Sie, dass die MEMORY-Speicher-Engine keine Blob-/Text-Spalten unterstützt, wenn Sie also django.db.models.TextField wird das für Sie nicht funktionieren.

14voto

Daniel Roseman Punkte 565786

Ich kann Ihre Hauptfrage nicht beantworten, aber es gibt ein paar Dinge, die Sie tun können, um die Dinge zu beschleunigen.

Stellen Sie zunächst sicher, dass Ihre MySQL-Datenbank für die Verwendung von InnoDB eingerichtet ist. Dann kann es Transaktionen verwenden, um den Zustand der Datenbank vor jedem Test zurückzusetzen, was meiner Erfahrung nach zu einer enormen Beschleunigung geführt hat. Sie können einen Datenbank-Init-Befehl in Ihrer settings.py übergeben (Django 1.2 Syntax):

DATABASES = {
    'default': {
            'ENGINE':'django.db.backends.mysql',
            'HOST':'localhost',
            'NAME':'mydb',
            'USER':'whoever',
            'PASSWORD':'whatever',
            'OPTIONS':{"init_command": "SET storage_engine=INNODB" } 
        }
    }

Zweitens müssen Sie nicht jedes Mal die Süd-Migrationen durchführen. einstellen SOUTH_TESTS_MIGRATE = False in Ihrer settings.py und die Datenbank wird mit einfachem syncdb erstellt, was viel schneller ist, als alle historischen Migrationen zu durchlaufen.

10voto

Potr Czachur Punkte 2056

Sie können doppeltes Tweaken durchführen:

  • Transaktions-Tabellen verwenden: Der anfängliche Zustand der Fixtures wird nach jedem TestCase durch ein Datenbank-Rollback gesetzt.
  • Legen Sie Ihr Datenbankdatenverzeichnis auf die Ramdisk: Sie werden viel gewinnen, was die Erstellung der Datenbank betrifft, und auch die Ausführung der Tests wird schneller sein.

Ich wende beide Tricks an und bin sehr zufrieden.

Wie man es für MySQL unter Ubuntu einrichtet:

$ sudo service mysql stop
$ sudo cp -pRL /var/lib/mysql /dev/shm/mysql

$ vim /etc/mysql/my.cnf
# datadir = /dev/shm/mysql
$ sudo service mysql start

Achtung, das ist nur zum Testen, nach dem Neustart ist die Datenbank aus dem Speicher verloren!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X