Wyłącz migracje podczas uruchamiania testów jednostkowych w Django 1.7


110

Django 1.7 wprowadziło migracje baz danych .

Podczas uruchamiania testów jednostkowych w Django 1.7 wymusza migrację , która zajmuje dużo czasu. Chciałbym więc pominąć migracje django i stworzyć bazę danych w ostatecznym stanie.

Wiem, że ignorowanie migracji może być złą praktyką, ponieważ ta część kodu nie zostanie przetestowana. Ale tak nie jest: przeprowadzam pełne migracje na serwerze testowym CI (jenkins). Chcę tylko pominąć migracje w moich lokalnych testach, w których liczy się szybkość.


Pewien kontekst:

Aż do Django 1.6 , kiedy używałem South, używałem ustawienia SOUTH_TESTS_MIGRATE :

Domyślnie polecenie syncdb języka South również zastosuje migracje, jeśli jest uruchomione w trybie nieinteraktywnym, co obejmuje również przeprowadzanie testów - będzie uruchamiane przy każdej migracji za każdym razem, gdy uruchomisz testy.

Jeśli chcesz, aby moduł uruchamiający testy używał syncdb zamiast migracji - na przykład, jeśli migracja trwa zbyt długo - po prostu ustaw SOUTH_TESTS_MIGRATE = False w settings.py.

Jednak syncdb już nie istnieje, teraz jest migrowany .

I od Django 1.8 Użyję --keepdb parametr:

Opcji --keepdb można użyć do zachowania testowej bazy danych między przebiegami testów. Ma to tę zaletę, że pomija zarówno akcje tworzenia, jak i niszczenia, co znacznie skraca czas uruchamiania testów, szczególnie tych w dużym zestawie testów. Jeśli testowa baza danych nie istnieje, zostanie utworzona przy pierwszym uruchomieniu, a następnie zachowana przy każdym kolejnym uruchomieniu. Wszelkie niezastosowane migracje zostaną również zastosowane do testowej bazy danych przed uruchomieniem zestawu testów.

Więc to pytanie ogranicza się do Django 1.7.


Twierdzę, że podczas UT naprawdę nie uruchamiasz migracji w sposób, który je testuje, ponieważ DB, z którym zaczynasz, nie istnieje. Testowanie migracji odbywa się tak naprawdę tylko podczas migracji istniejącej bazy danych. Ten biznes migracyjny 1.7 jest pierwszym prawdziwym zadziorem pod siodłem, które miałem z Django, ale jest naprawdę duży irytujący. Południe przynajmniej uzyskało odpowiedni scenariusz testowy dla migracji.
boatcoder

django-test-without-migrationsPakiet był bardzo przydatne dla mnie, może chcesz zmienić zaakceptowanej odpowiedzi stackoverflow.com/a/28993456/200224
Andy

Jeśli to możliwe, wolę unikać dodawania nowych zależności.
David Arcos

Odpowiedzi:


79

Spójrz na to obejście , opublikowane przez Berniego Sumption na liście mailingowej deweloperów Django:

Jeśli makemigracje nie zostały jeszcze uruchomione, polecenie „migrate” traktuje aplikację jako niemigrowaną i tworzy tabele bezpośrednio z modeli, tak jak w przypadku programu syncdb w wersji 1.6. Zdefiniowałem nowy moduł ustawień tylko dla testów jednostkowych o nazwie „settings_test.py”, który importuje * z głównego modułu ustawień i dodaje ten wiersz:

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

Następnie wykonuję takie testy:

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

Ci głupcy myślą, że aplikacja nie jest migrowana, więc za każdym razem, gdy tworzona jest testowa baza danych, odzwierciedla ona aktualną strukturę models.py.

W Django 1.9 sytuacja nieco się poprawiła i możesz ustawić wartość na None:

MIGRATION_MODULES = {"myapp": brak}


9
Zauważ, że myapp.migrations_not_used_in_testsmoduł nie powinien istnieć.
bmihelac

4
Oprócz komentarza @bmihelac dotyczącego nieistniejącego modułu, ciąg modułu musi zawierać podłańcuch „migrations”. Dlaczego? Zobacz: github.com/django/django/blob/stable/1.7.x/django/db/migrations /…
nealtodd


1
TY. Dzięki temu udało mi się skrócić testy jednostkowe z 13 do 4 sekund. Ponadto, więcej przyrostów prędkości można znaleźć, używając sqlite do testowania. U mnie używanie postgres do testów zajmuje 5,5 sekundy, a sqlite 4 sekundy.
Gattster

21
Z komentarzy do streszczenia @ nealtodda, oto link do rozwiązania, które pozwala uniknąć niektórych pułapek i jest bardzo proste: gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
djsutho

72

Oto koniec mojego pliku ustawień:

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

na podstawie tego fragmentu

Migracje wyłączyłem tylko wtedy, gdy są uruchomione testy


1
Miły! Dodałbym również __setitem__(self, *_)metodę, ponieważ mieliśmy problem z aplikacjami, które ustawiały własną migrację, jak settings.MIGRATION_MODULES['chroniker'] = 'db_migrations'
Zhe Li

1
Dziękuję bardzo za to, to jedyna rzecz, jaką znalazłem, która faktycznie działa.
fluffels

To już nie działa w Django 1.9 podczas uruchamiania testów w trybie równoległym. Używając normalnego testowania nierównoległego, nadal działa dobrze, ale przełączenie do trybu równoległego powoduje błędy, które nie pozwalają na znalezienie tabel.
LS55321

@LeeSemel w trybie równoległym prawdopodobnie chcesz użyć rozwiązania z rlmv
Guillaume Vincent

@guillaumevincent Mam ten sam problem podczas używania django-test-without-migrations w trybie równoległym
LS55321


3

Aktualizacja : nieważne, ta zmiana została cofnięta przed wydaniem wersji 1.10. Miejmy nadzieję, że powróci w przyszłej wersji.


Należy zauważyć, że od wersji Django 1.10 można to kontrolować za pomocą ustawień testowej bazy danych.

MIGROWAĆ

Domyślna: True

Jeśli jest ustawiona na False, Django nie będzie używać migracji do tworzenia testowej bazy danych.



1

Dla django 1.9 i nowszych odpowiedź Guillaume Vincent już nie działa, więc oto nowe rozwiązanie:

Używam tego fragmentu kodu w moim pliku ustawień, po definicji INSTALLED_APPS

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

Iteruje po wszystkich zainstalowanych aplikacjach i oznacza każdą jako nie posiadającą modułu migracji. Więcej informacji można znaleźć w dokumentacji django .

Za pomocą tego fragmentu możesz uruchomić swoje testy, ustawiając zmienną środowiskową TESTS_WITHOUT_MIGRATIONS, np:

TESTS_WITHOUT_MIGRATIONS=1 ./manage.py test

1

Właśnie zastanawiam się, jak wyłączyć migracje po django 1.10, może to komuś pomoże. Tutaj jest link na git

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

    def __getitem__(self, item):
        return None

DATABASES = DisableMigrations()

MIGRATION_MODULES = DisableMigrations()

Migracje dla django 1.10 składają się z dwóch części, spójrz na load_disk i rejestrator

Część load_diskmodelu aplikacji dla migracji, która zostanie dodana w INSTALL_APP I część recorderdla połączenia z bazą danych Dla wersji wcześniejszej niż 1.9 musimy ustawić MIGRATION_MODULES={'do.not.migrate':'notmigrations'}kiedy uruchamiasz test Teraz musimy go ustawić Brak tak MIGRATION_MODULES={'do.not.migrate':None} Jeśli nie chcemy robić migracji dla żadnej aplikacji , po prostu przedłuż dyktando i wróć Nonepogetitem funkcji, i zrób to samo w DATABASES, to jest właściwa rzecz, którą musisz zrobić

PS: W przypadku polecenia musisz określić --setting=module.path.settings_test_snippetpo test PPS Jeśli pracujesz z pycharm, nie ustawiaj--settings opcji na Run/Debug configurations, po prostu dodaj ścieżkę settings_test_snippet.pyw ustawieniach niestandardowych. Po prostu będzie dobrze !!

cieszyć się

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.