Czy istnieje możliwość pisania unittestów django bez konfigurowania bazy danych? Chcę przetestować logikę biznesową, która nie wymaga konfiguracji bazy danych. I chociaż konfiguracja bazy danych jest szybka, naprawdę nie potrzebuję jej w niektórych sytuacjach.
126
Odpowiedzi:
Możesz podklasować DjangoTestSuiteRunner i przesłonić metody setup_databases i teardown_databases do przekazania.
Utwórz nowy plik ustawień i ustaw TEST_RUNNER na nowo utworzoną klasę. Następnie podczas uruchamiania testu określ nowy plik ustawień za pomocą flagi --settings.
Oto co zrobiłem:
Utwórz niestandardowy biegacz kombinezonu testowego podobny do tego:
Utwórz ustawienia niestandardowe:
Kiedy uruchamiasz swoje testy, uruchom je w następujący sposób z flagą --settings ustawioną na nowy plik ustawień:
AKTUALIZACJA: kwiecień / 2018
Od wersji Django 1.8 moduł został przeniesiony do .
django.test.simple.DjangoTestSuiteRunner
'django.test.runner.DiscoverRunner'
Aby uzyskać więcej informacji, sprawdź oficjalną sekcję dokumentacji o niestandardowych uruchomieniach testów.
źródło
--testrunner
opcji.Ogólnie testy w aplikacji można podzielić na dwie kategorie
Django obsługuje testy jednostkowe i integracyjne.
Testy jednostkowe nie wymagają konfigurowania i niszczenia bazy danych, a te powinniśmy odziedziczyć po SimpleTestCase .
W przypadku przypadków testowych integracji dziedziczenie z TestCase z kolei dziedziczy z TransactionTestCase i skonfiguruje i zburzy bazę danych przed uruchomieniem każdego testu.
Ta strategia zapewni, że baza danych zostanie utworzona i zniszczona tylko dla przypadków testowych, które mają dostęp do bazy danych, a zatem testy będą bardziej wydajne
źródło
Z
django.test.simple
Więc zastąp
DiscoverRunner
zamiastDjangoTestSuiteRunner
.Użyj w ten sposób:
źródło
Zdecydowałem się odziedziczyć
django.test.runner.DiscoverRunner
i dodać kilka elementów dorun_tests
metody.Mój pierwszy dodatek sprawdza, czy ustawienie bazy danych jest konieczne i pozwala na uruchomienie normalnej
setup_databases
funkcjonalności, jeśli baza danych jest konieczna. Mój drugi dodatek pozwala normalnieteardown_databases
działać, jeślisetup_databases
metoda była dozwolona.W moim kodzie założono, że każda sprawa TestCase, która dziedziczy z
django.test.TransactionTestCase
(a tym samymdjango.test.TestCase
) wymaga skonfigurowania bazy danych. Zrobiłem to założenie, ponieważ doktorzy Django mówią:https://docs.djangoproject.com/en/1.6/topics/testing/tools/#django.test.SimpleTestCase
mysite / scripts / settings.py
Na koniec dodałem następujący wiersz do pliku settings.py mojego projektu.
mysite / settings.py
Teraz, gdy uruchamiam tylko testy niezależne od db, mój zestaw testów działa o rząd wielkości szybciej! :)
źródło
Zaktualizowano: zapoznaj się również z tą odpowiedzią dotyczącą korzystania z narzędzia innej firmy
pytest
.@Cesar ma rację. Po przypadkowym uruchomieniu
./manage.py test --settings=no_db_settings
, bez określenia nazwy aplikacji, moja programistyczna baza danych została wyczyszczona.Dla bezpieczniejszego sposobu używaj tego samego
NoDbTestRunner
, ale w połączeniu z następującymimysite/no_db_settings.py
:Musisz utworzyć bazę danych o nazwie
_test_mysite_db
przy użyciu narzędzia zewnętrznej bazy danych. Następnie uruchom następujące polecenie, aby utworzyć odpowiednie tabele:Jeśli używasz południa, uruchom również następujące polecenie:
DOBRZE!
Możesz teraz przeprowadzać testy jednostkowe niesamowicie szybko (i bezpiecznie) poprzez:
źródło
Jako alternatywę dla zmodyfikowania ustawień w celu uczynienia NoDbTestRunner „bezpiecznym”, oto zmodyfikowana wersja NoDbTestRunner, która zamyka bieżące połączenie z bazą danych i usuwa informacje o połączeniu z ustawień i obiektu połączenia. U mnie działa, przetestuj go w swoim środowisku, zanim na nim polegasz :)
źródło
__getitem__
. Użyjconnections._connections.default
, aby uzyskać dostęp do obiektu.Innym rozwiązaniem byłoby pozostawienie klasy testowej po prostu dziedziczenia z
unittest.TestCase
dowolnej klasy testowej Django zamiast jej. Dokumentacja Django ( https://docs.djangoproject.com/en/2.0/topics/testing/overview/#writing-tests ) zawiera następujące ostrzeżenie:Jeśli jednak Twój test nie korzysta z bazy danych, to ostrzeżenie nie musi Cię martwić i możesz czerpać korzyści z braku konieczności uruchamiania każdego przypadku testowego w transakcji.
źródło
Powyższe rozwiązania też są w porządku. Ale poniższe rozwiązanie również skróci czas tworzenia bazy danych, jeśli jest więcej migracji. Podczas testów jednostkowych uruchomienie syncdb zamiast uruchamiania wszystkich migracji na południe będzie znacznie szybsze.
źródło
Mój host sieciowy pozwala tylko na tworzenie i usuwanie baz danych z ich internetowego interfejsu graficznego, więc podczas próby uruchomienia otrzymywałem komunikat „Wystąpił błąd podczas tworzenia testowej bazy danych: odmowa uprawnień”
python manage.py test
.Miałem nadzieję, że użyję opcji --keepdb do django-admin.py, ale wydaje się, że nie jest ona już obsługiwana od wersji Django 1.7.
Skończyło się na tym, że zmodyfikowałem kod Django w ... / django / db / backends / creation.py, a konkretnie funkcje _create_test_db i _destroy_test_db.
Ponieważ
_create_test_db
zakomentowałemcursor.execute("CREATE DATABASE ...
linię i zastąpiłem ją,pass
abytry
blok nie był pusty.Bo
_destroy_test_db
właśnie wykomentowałemcursor.execute("DROP DATABASE
- nie musiałem go niczym zastępować, ponieważ w bloku (time.sleep(1)
) było już inne polecenie .Potem moje testy przebiegły dobrze - chociaż osobno skonfigurowałem wersję test_ mojej zwykłej bazy danych.
Nie jest to oczywiście świetne rozwiązanie, ponieważ zepsuje się, jeśli Django zostanie zaktualizowane, ale miałem lokalną kopię Django z powodu używania virtualenv, więc przynajmniej mam kontrolę nad tym, kiedy / czy zaktualizuję do nowszej wersji.
źródło
Inne rozwiązanie, o którym nie wspomniano: było to dla mnie łatwe do zaimplementowania, ponieważ mam już wiele plików ustawień (dla lokalnego / tymczasowego / produkcyjnego), które dziedziczą po base.py. Więc w przeciwieństwie do innych ludzi nie musiałem nadpisywać BAZ DANYCH ['domyślne'], ponieważ BAZY DANYCH nie są ustawione w base.py
SimpleTestCase nadal próbował połączyć się z moją testową bazą danych i uruchomić migracje. Kiedy stworzyłem plik config / settings / test.py, który nie ustawiał baz danych na nic, moje testy jednostkowe działały bez niego. Pozwoliło mi to na użycie modeli, które miały klucz obcy i unikalne pola ograniczeń. (Odwrotne wyszukiwanie klucza obcego, które wymaga wyszukiwania bazy danych, kończy się niepowodzeniem).
(Django 2.0.6)
Fragmenty kodu PS
źródło
Używając testowego biegacza do nosa (django-nose), możesz zrobić coś takiego:
my_project/lib/nodb_test_runner.py
:W swoim
settings.py
możesz tam określić biegacza testowego, tjTEST_RUNNER = 'lib.nodb_test_runner.NoDbTestRunner' . # Was 'django_nose.NoseTestSuiteRunner'
LUB
Chciałem go tylko do uruchamiania określonych testów, więc uruchamiam go tak:
źródło