Deaktivieren Sie Migrationen, wenn Sie Unit-Tests in Django 1.7 ausführen


110

Django 1.7 führte Datenbankmigrationen ein .

Wenn Sie die Komponententests in Django 1.7 ausführen, wird eine Migration erzwungen , die lange dauert. Daher möchte ich die Django-Migrationen überspringen und die Datenbank im Endzustand erstellen.

Ich weiß, dass das Ignorieren der Migrationen eine schlechte Praxis sein kann, da dieser Teil des Codes nicht getestet werden würde. Dies ist jedoch nicht der Fall: Ich führe die vollständigen Migrationen auf dem CI-Testserver (Jenkins) aus. Ich möchte nur die Migrationen in meinen lokalen Tests überspringen, bei denen es auf die Geschwindigkeit ankommt.


Ein Kontext:

Bis Django 1.6 habe ich bei Verwendung von South die Einstellung SOUTH_TESTS_MIGRATE verwendet :

Standardmäßig wendet der Befehl syncdb von South auch Migrationen an, wenn er im nicht interaktiven Modus ausgeführt wird. Dies gilt auch für die Ausführung von Tests. Bei jeder Ausführung Ihrer Tests wird jede Migration ausgeführt.

Wenn Sie möchten, dass der Testläufer syncdb anstelle der Migration verwendet, z. B. wenn Ihre Migrationen viel zu lange dauern, setzen Sie einfach SOUTH_TESTS_MIGRATE = False in settings.py.

Allerdings syncdb existieren mehr nicht, jetzt ist es Migrate .

Und ab Django 1.8 verwende ich den Parameter --keepdb :

Mit der Option --keepdb kann die Testdatenbank zwischen den Testläufen beibehalten werden. Dies hat den Vorteil, dass sowohl die Erstellungs- als auch die Zerstörungsaktionen übersprungen werden, was die Zeit zum Ausführen von Tests erheblich verkürzt, insbesondere in einer großen Testsuite. Wenn die Testdatenbank nicht vorhanden ist, wird sie beim ersten Lauf erstellt und dann für jeden nachfolgenden Lauf beibehalten. Nicht angewendete Migrationen werden auch auf die Testdatenbank angewendet, bevor die Testsuite ausgeführt wird.

Diese Frage ist also auf Django 1.7 beschränkt.


Ich würde argumentieren, dass Sie die Migrationen während UT wirklich nicht so ausführen, dass sie getestet werden, da die DB, mit der Sie beginnen, nicht vorhanden ist. Das Testen von Migrationen findet wirklich nur statt, wenn Sie eine vorhandene Datenbank migrieren. Dieses 1,7-Migrationsgeschäft ist der erste echte Grat unter dem Sattel, den ich mit Django hatte, aber es ist ein wirklich großer Irritant. South hat zumindest das richtige Testszenario für Migrationen.
Bootscodierer

Das django-test-without-migrationsPaket war wirklich praktisch für mich, vielleicht möchten Sie die akzeptierte Antwort auf stackoverflow.com/a/28993456/200224
Andy

Wenn möglich, vermeide ich lieber das Hinzufügen neuer Abhängigkeiten.
David Arcos

Antworten:


79

Schauen Sie sich diese Problemumgehung an , die Bernie Sumption auf der Mailingliste der Django-Entwickler veröffentlicht hat:

Wenn makemigrations noch nicht ausgeführt wurde, behandelt der Befehl "migrate" eine App als nicht migriert und erstellt Tabellen direkt aus den Modellen, genau wie es syncdb in 1.6 getan hat. Ich habe ein neues Einstellungsmodul nur für Komponententests mit dem Namen "settings_test.py" definiert, das * aus dem Haupteinstellungsmodul importiert und diese Zeile hinzufügt:

MIGRATION_MODULES = {"myapp": "myapp.migrations_not_used_in_tests"}

Dann führe ich Tests wie folgt durch:

DJANGO_SETTINGS_MODULE = "myapp.settings_test" python manage.py test

Diese Dummköpfe denken, dass die App nicht migriert ist, und spiegeln jedes Mal, wenn eine Testdatenbank erstellt wird, die aktuelle Struktur von models.py wider.

In Django 1.9 hat sich diese Situation etwas verbessert , und Sie können den Wert auf Folgendes einstellen None:

MIGRATION_MODULES = {"myapp": Keine}


9
Beachten Sie, dass das myapp.migrations_not_used_in_testsModul nicht vorhanden sein sollte.
Bmihelac

4
Zusätzlich zu dem Kommentar @bmihelac zu dem nicht vorhandenen Modul muss die Modulzeichenfolge den Teilstring 'migrations' enthalten. Weitere Informationen finden Sie unter: github.com/django/django/blob/stable/1.7.x/django/db/migrations /…
Nealtodd

7
Ein Kern einer Funktion zum dynamischen Erstellen von MIGRATION_MODULES in settings_test.py: gist.github.com/nealtodd/2869341f38f5b1eeb86d
nealtodd

1
TY. Dadurch konnte ich meine Unit-Tests von 13 Sekunden auf 4 Sekunden reduzieren. Weitere Geschwindigkeitsgewinne können durch die Verwendung von SQLite zum Testen erzielt werden. Für mich dauert die Verwendung von Postgres für Tests 5,5 Sekunden, für SQLite jedoch 4 Sekunden.
Gattster

21
Aus den Kommentaren von @ nealtodds Kern ist hier ein Link zu einer Lösung, die einige der Fallstricke vermeidet und super einfach ist: gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
djsutho

72

Hier ist das Ende meiner Einstellungsdatei:

class DisableMigrations(object):

    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None


TESTS_IN_PROGRESS = False
if 'test' in sys.argv[1:] or 'jenkins' in sys.argv[1:]:
    logging.disable(logging.CRITICAL)
    PASSWORD_HASHERS = (
        'django.contrib.auth.hashers.MD5PasswordHasher',
    )
    DEBUG = False
    TEMPLATE_DEBUG = False
    TESTS_IN_PROGRESS = True
    MIGRATION_MODULES = DisableMigrations()

basierend auf diesem Snippet

Ich habe Migrationen nur deaktiviert, wenn Tests ausgeführt werden


1
Nett! Ich würde auch __setitem__(self, *_)Methode hinzufügen , weil wir Probleme mit Apps hatten, die ihre eigene Migration wiesettings.MIGRATION_MODULES['chroniker'] = 'db_migrations'
Zhe Li

1
Vielen Dank dafür, es ist das einzige, was ich gefunden habe, das tatsächlich funktioniert.
Fluffels

Dies funktioniert in Django 1.9 nicht mehr, wenn Tests im parallelen Modus ausgeführt werden. Bei normalen nicht parallelen Tests funktioniert es weiterhin einwandfrei, aber das Umschalten in den parallelen Modus führt zu Fehlern, bei denen keine Tabellen gefunden werden.
LS55321

@ LeeSemel im parallelen Modus möchten Sie wahrscheinlich die Lösung von rlmv
Guillaume Vincent

@guillaumevincent Ich habe das gleiche Problem bei der Verwendung von Django-Test-ohne-Migrationen im parallelen Modus
LS55321


3

Update : Egal, diese Änderung wurde vor der Veröffentlichung des 1.10-Finales rückgängig gemacht . Hoffentlich wird es in einer zukünftigen Version zurückkehren.


Beachten Sie, dass dies ab Django 1.10 durch eine Testdatenbankeinstellung gesteuert werden kann.

WANDERN

Standard: True

Wenn diese Option Falseaktiviert ist, verwendet Django keine Migrationen zum Erstellen der Testdatenbank.



1

Für Django 1.9 und höher funktioniert die Antwort von Guillaume Vincent nicht mehr. Hier ist eine neue Lösung:

Ich verwende dieses Snippet in meiner Einstellungsdatei nach der Definition des INSTALLED_APPS

if os.environ.get('TESTS_WITHOUT_MIGRATIONS', False):
    MIGRATION_MODULES = {
        app.split('.')[-1]: None for app in INSTALLED_APPS
    }

Es iteriert über alle installierten Apps und markiert jede als ohne Migrationsmodul. Weitere Informationen finden Sie in den Django-Dokumenten .

Mit diesem Snippet können Sie Ihre Tests ausführen und die Umgebungsvariable festlegen TESTS_WITHOUT_MIGRATIONS, z.

TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test

1

Ich finde gerade heraus, wie man Migrationen nach Django 1.10 deaktiviert, vielleicht könnte es jemandem helfen. Hier ist der Link bei git

class DisableMigrations(dict):
    def __contains__(self, item):
        return True

    def __getitem__(self, item):
        return None

DATABASES = DisableMigrations()

MIGRATION_MODULES = DisableMigrations()

Migrationen für Django 1.10 bestehen aus zwei Teilen. Schauen Sie sich load_disk und recorder an

Der Teil load_diskfür das Migrationsmodell der App, der hinzugefügt wird, INSTALL_APP und der Teil recorderfür die Datenbankverbindung Für die Version vor 1.9 müssen wir festgelegt werden, MIGRATION_MODULES={'do.not.migrate':'notmigrations'}wenn Sie den Test ausführen. Jetzt müssen wir ihn festlegen. Keine wie MIGRATION_MODULES={'do.not.migrate':None} Also, wenn wir keine Migrationen für eine App durchführen möchten Erweitern Sie einfach ein Diktat und kehren Sie Nonezur getitemFunktion zurück, und machen Sie dasselbe bei DATABASES, das ist das Richtige, was Sie tun müssen

PS: Für Befehle müssen Sie --setting=module.path.settings_test_snippetnach test PPS angeben. Wenn Sie mit arbeiten pycharm, legen Sie keine--settings Optionen fest Run/Debug configurations, sondern fügen Sie einfach den Pfad von settings_test_snippet.pybei Benutzerdefinierte Einstellung hinzu. Das ist einfach gut !!

genießen

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.