Disabilitare le migrazioni durante l'esecuzione di unit test in Django 1.7


110

Django 1.7 ha introdotto le migrazioni del database .

Quando si eseguono gli unit test in Django 1.7, forza una migrazione , che richiede molto tempo. Quindi vorrei saltare le migrazioni di django e creare il database nello stato finale.

So che ignorare le migrazioni può essere una cattiva pratica, poiché quella parte del codice non verrebbe testata. Ma non è così: sto eseguendo le migrazioni complete nel server di test CI (jenkins). Voglio solo saltare le migrazioni nei miei test locali, dove la velocità conta.


Qualche contesto:

Fino a Django 1.6 , quando utilizzavo South, utilizzavo l' impostazione SOUTH_TESTS_MIGRATE :

Per impostazione predefinita, il comando syncdb di South applicherà anche le migrazioni se viene eseguito in modalità non interattiva, che include quando esegui i test: eseguirà ogni migrazione ogni volta che esegui i tuoi test.

Se vuoi che il test runner utilizzi syncdb invece di migrare, ad esempio se le tue migrazioni impiegano troppo tempo per essere applicate, imposta semplicemente SOUTH_TESTS_MIGRATE = False in settings.py.

Tuttavia, syncdb non esiste più, ora è migrato .

E da Django 1.8 userò il parametro --keepdb :

L'opzione --keepdb può essere utilizzata per preservare il database di test tra le esecuzioni di test. Questo ha il vantaggio di saltare sia le azioni di creazione che di distruzione, il che riduce notevolmente il tempo necessario per eseguire i test, specialmente quelli in una suite di test di grandi dimensioni. Se il database di test non esiste, verrà creato alla prima esecuzione e quindi conservato per ogni esecuzione successiva. Eventuali migrazioni non applicate verranno applicate anche al database di test prima di eseguire la suite di test.

Quindi questa domanda è limitata a Django 1.7.


Direi che durante l'UT, non stai davvero eseguendo le migrazioni in un modo che le collauda poiché il DB con cui inizi è inesistente. Il test delle migrazioni avviene in realtà solo quando si esegue la migrazione di un DB esistente. Questa attività di 1.7 migrazioni è la prima vera bava sotto sella che ho avuto con Django, ma è davvero una grande irritazione. Il sud almeno ha ottenuto lo scenario di test adatto alle migrazioni.
boatcoder

Il django-test-without-migrationspacchetto è stato davvero utile per me, potresti voler cambiare la risposta accettata a stackoverflow.com/a/28993456/200224
Andy

Preferisco evitare di aggiungere nuove dipendenze, se possibile.
David Arcos

Risposte:


79

Guarda questa soluzione alternativa , pubblicata da Bernie Sumption nella mailing list degli sviluppatori Django:

Se makemigrations non è stato ancora eseguito, il comando "migrate" tratta un'app come non migrata e crea tabelle direttamente dai modelli proprio come faceva syncdb nella 1.6. Ho definito un nuovo modulo delle impostazioni solo per gli unit test chiamato "settings_test.py", che importa * dal modulo delle impostazioni principali e aggiunge questa riga:

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

Quindi eseguo test come questo:

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

Ciò fa pensare che l'app non sia migrata e quindi ogni volta che viene creato un database di test, esso riflette la struttura corrente di models.py.

In Django 1.9, questa situazione è leggermente migliorata e puoi impostare il valore su None:

MIGRATION_MODULES = {"myapp": Nessuno}


9
Nota che il myapp.migrations_not_used_in_testsmodulo non dovrebbe esistere.
bmihelac

4
Oltre al commento che @bmihelac ha fatto sul modulo non esistente, la stringa del modulo deve contenere la sottostringa 'migrations', Per il motivo vedere: github.com/django/django/blob/stable/1.7.x/django/db/migrations /…
nealtodd

7
Una sintesi di una funzione per costruire MIGRATION_MODULES dinamicamente in settings_test.py: gist.github.com/nealtodd/2869341f38f5b1eeb86d
nealtodd

1
TY. Per questo motivo sono stato in grado di ridurre i miei test unitari da 13 secondi a 4 secondi. Inoltre, è possibile ottenere maggiori guadagni di velocità utilizzando sqlite per i test. Per me, l'utilizzo di postgres per i test richiede 5,5 secondi, ma sqlite impiega 4 secondi.
Gattster

21
Dai commenti dell'essenza di @nealtodd ecco un link a una soluzione che evita alcune delle insidie ​​ed è semplicissima: gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
djsutho

72

Ecco la fine del mio file di impostazioni:

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()

in base a questo frammento

Ho disabilitato le migrazioni solo durante l'esecuzione dei test


1
Bello! Vorrei aggiungere anche il __setitem__(self, *_)metodo perché abbiamo avuto problemi con le app che impostano la propria migrazione come settings.MIGRATION_MODULES['chroniker'] = 'db_migrations'
Zhe Li

1
Grazie mille per questo, è l'unica cosa che ho scoperto che funziona davvero.
lanugine

Questo non funziona più in Django 1.9 quando si eseguono test in modalità parallela. Utilizzando normali test non paralleli, continua a funzionare correttamente, ma il passaggio alla modalità parallela genera errori che le tabelle non vengono trovate.
LS55321

@LeeSemel in modalità parallela probabilmente vorrai usare la soluzione di rlmv
Guillaume Vincent

@ guillaumevincent ho lo stesso problema quando utilizzo django-test-without-migrations in modalità parallela
LS55321


3

Aggiornamento : non importa, questa modifica è stata annullata prima del rilascio della versione 1.10 finale. Si spera che torni in una versione futura.


Nota che a partire da Django 1.10 questo può essere controllato da un'impostazione del database di prova.

MIGRARE

Predefinito: True

Se impostato su False, Django non utilizzerà le migrazioni per creare il database di test.



1

Per django 1.9 e versioni successive la risposta di Guillaume Vincent non funziona più, quindi ecco una nuova soluzione:

Sto usando questo frammento nel mio file delle impostazioni, dopo la definizione del file INSTALLED_APPS

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

Esegue l'iterazione su tutte le app installate e contrassegna ciascuna come priva di modulo di migrazione. Vedere la documentazione di django per ulteriori informazioni .

Usando questo snippet puoi eseguire i tuoi test, impostando la variabile d'ambiente TESTS_WITHOUT_MIGRATIONS, ad esempio:

TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test

1

Ho appena scoperto come disabilitare le migrazioni dopo django 1.10, potrebbe essere d'aiuto per qualcuno. Ecco il link su git

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

    def __getitem__(self, item):
        return None

DATABASES = DisableMigrations()

MIGRATION_MODULES = DisableMigrations()

Migrations for django 1.10 ha due parti, guarda load_disk e recorder

La parte del load_diskmodello di app per le migrazioni che deve essere aggiunta a INSTALL_APP E la parte di recorderper la connessione al database Per la versione precedente alla 1.9 è necessario impostare MIGRATION_MODULES={'do.not.migrate':'notmigrations'}quando si esegue il test Ora è necessario impostarlo Nessuno come MIGRATION_MODULES={'do.not.migrate':None} Quindi se non si desidera eseguire migrazioni per nessuna app , estendi semplicemente un dict e torna Noneper la getitemfunzione, e fai lo stesso in DATABASES, questa è la cosa giusta che devi fare

PS: per il comando, è necessario specificare --setting=module.path.settings_test_snippetdopo test PPS. Se stai lavorando pycharm, non impostare le --settings opzioni su Run/Debug configurations, aggiungi semplicemente il percorso di settings_test_snippet.pyImpostazioni personalizzate. Va bene così !!

godere

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.