Jak rozłożyć testy jednostkowe django na wiele plików?

126
  • Mam aplikację python-django
  • Używam frameworka do testów jednostkowych
  • Testy są uporządkowane w pliku „tests.py” w katalogu modułów
  • Przeprowadzam testy przez ./manage.py test app

Teraz..

  • tests.pyPlik staje się dość duża / na terenie / brudny
  • Chciałbym podzielić tests.pysię na mniejsze zbiory testów ...

W jaki sposób?

John Mee
źródło

Odpowiedzi:

47

Zachowanie zmieniło się w Django 1.6, więc nie ma już potrzeby tworzenia pakietu. Po prostu nazwij swoje pliki test*.py.

Z dokumentacji Django 1.7

Podczas uruchamiania testów domyślnym zachowaniem narzędzia testowego jest znalezienie wszystkich przypadków testowych (czyli podklas unittest.TestCase) w dowolnym pliku, którego nazwa zaczyna się od test, automatycznie tworzy zestaw testów z tych przypadków testowych, i uruchom ten pakiet.

Z dokumentacji Django 1.6 ,

Wykrywanie testów jest oparte na wykrywaniu testów wbudowanym w moduł Unittest. Domyślnie spowoduje to wykrycie testów w dowolnym pliku o nazwie „test * .py” w bieżącym katalogu roboczym.

Poprzednie zachowanie, z dokumentacji Django 1.5 :

Podczas uruchamiania testów domyślnym zachowaniem narzędzia testowego jest znalezienie wszystkich przypadków testowych (czyli podklas unittest.TestCase) w models.py i tests.py, automatyczne utworzenie zestawu testów z tych przypadków testowych, i uruchom ten pakiet.

Istnieje drugi sposób zdefiniowania zestawu testów dla modułu: jeśli zdefiniujesz funkcję o nazwie suite () w models.py lub tests.py, moduł uruchamiający testy Django użyje tej funkcji do skonstruowania zestawu testów dla tego modułu. Jest to zgodne z sugerowaną organizacją testów jednostkowych. Zobacz dokumentację języka Python, aby uzyskać więcej informacji na temat tworzenia złożonego zestawu testów.

osa
źródło
4
W django 2.6 tak naprawdę nic nie odkrywa…
LtWorf
2
Obecnie używam Django 1.10, chciałem umieścić wszystkie moje test*.pypliki w folderze o nazwie, testsaby utrzymać folder w czystości - jest to możliwe, ale musisz uruchomić ./manage.py test app.testsi wszystkie względne importy muszą wzrosnąć o jeden poziom ( from .modelsstaje się from ..models).
Scott Stevens
123

Zauważ, że to podejście nie jest już poprawne od Django 1.6, zobacz ten post .

Możesz stworzyć testsfolder z ___init___.pywnętrzem (aby stał się pakietem). Następnie dodajesz tam pliki .py testu podziału i importujesz je wszystkie w formacie ___init___.py.

To znaczy: Zastąp test.pyplik modułem, który wygląda i działa jak plik:

Utwórz testskatalog w danej aplikacji

aplikacja
app \ models.py
app \ views.py
app \ tests
app \ tests \ __ init__.py
app \ tests \ bananas.py
app \ tests \ apples.py

Zaimportuj podmoduły do app\tests\__init__.py:

from bananas import *
from apples import *

Teraz możesz używać ./manage.py tak, jakby wszystkie znajdowały się w jednym pliku:

./manage.py test app.some_test_in_bananas
Tomasz Zieliński
źródło
1
Doh. Miałeś na myśli utworzenie modułu „testy” w aplikacji, którą testuję; a nie nowa aplikacja o nazwie testy. Teraz rozumiem. Niesamowite. Dzięki!
John Mee,
@John: Nie mogę już rozpoznać swojej odpowiedzi! :-) Ale masz całkowitą rację, że było to zbyt niejasne, nawet jeśli poprawne - twoje przykłady wyjaśniają, w przeciwieństwie do mojego pierwotnego sformułowania.
Tomasz Zieliński
2
@Tomasz .. Twoje słowa wciąż tam są - całkowicie nienaruszone. Po prostu trochę to rozwinąłem, odkąd umieściłeś mnie na właściwej drodze.
John Mee,
@John: Wcale nie byłem zły, jeśli to masz na myśli :) Zabawnie było zobaczyć moją własną odpowiedź w nieco innym kształcie
Tomasz Zieliński
4
@jMyles, jeśli przez "zwykły tester django" masz na myśli, python manage.py test myappto w rzeczywistości ta odpowiedź działa dobrze. (właśnie spróbowałem)
Kirk Woll,
27

Odpowiedź podana przez Tomasza jest prawidłowa. Jednak upewnienie się, że importowane __init__.pypliki są zgodne ze strukturą plików , może być uciążliwe .

Aby automatycznie wykryć wszystkie testy w folderze , możesz dodać to w __init__.py:

import unittest

def suite():   
    return unittest.TestLoader().discover("appname.tests", pattern="*.py")

Umożliwi to uruchomienie, ./manage.py test appnameale nie będzie obsługiwać wykonywania określonych testów. Aby to zrobić, możesz użyć tego kodu (również w __init__.py):

import pkgutil
import unittest

for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
    module = loader.find_module(module_name).load_module(module_name)
    for name in dir(module):
        obj = getattr(module, name)
        if isinstance(obj, type) and issubclass(obj, unittest.case.TestCase):
            exec ('%s = obj' % obj.__name__)

Teraz możesz uruchomić wszystkie swoje testy za pośrednictwem manage.py test applub konkretne testy za pośrednictwemmanage.py test app.TestApples

Bryce Drennan
źródło
Gdzie kładziesz drugi element?
rh0dium
Oba elementy wchodzą do__init__.py
Bryce Drennan
Zwróć uwagę, że jeśli którakolwiek z nazw twoich pakietów testowych pokrywa się z nazwami modułów najwyższego poziomu, które są importowane podczas uruchamiania testu, fragment pkgutil spowoduje niepowodzenie importu, ponieważ testy zostaną dodane jako sys.modules[packagename]. Szybkim obejściem jest to, delktóre powoduje problemy po powyższym. (Lub możesz zmienić nazwy swoich folderów;))
Paul Fenney
To jest świetne, ale napotkałem błąd, w którym podczas uruchamiania testu na poziomie aplikacji ( python manage.py test appName) drugi bit kodu zgłosiłby błąd stwierdzający, że __path__nie jest dostępny. Uniknąłem tego, zawijając drugi fragment w if '__path__' in locals():czek, co załatwiło sprawę . Dziękuję za odpowiedź!
alukach
1
+1 zapewnia to również, że plik init jest zgodny z powszechnymi standardami kodowania, tj. Nie zawiera * lub niewykorzystanych importów
Martin B.
13

Po prostu utwórz strukturę katalogów w następujący sposób:

myapp/
    __init__.py
    tests/
        __init__.py
        test_one.py
        test_two.py
        ...
    ...

I python manage.py test myappbędzie działać zgodnie z oczekiwaniami.

spiderlama
źródło
2

Nie ma potrzeby kodowania niczego w init. Po prostu utwórz podkatalog w swojej aplikacji. Jedynym wymogiem jest to, aby nie nazywać tego testami * Na przykład

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py
MaxBlax360
źródło
1
Dlaczego nie można tego nazwać czymś, co zaczyna się od „testów”?
Serp C
Używam tej odpowiedzi w Django 1.11.4. Powody, dla których warto go używać: (1) plik „app / testing / __ init__.py” pozostaje pusty oraz (2) polecenie pozostaje podstawową „aplikacją testową python manage.py”
rprasad
2

Django 2.2 to prosta i dość dobrym rozwiązaniem mogłoby być stworzenie testfolderu wewnątrz aplikacji, można umieścić powiązane test_...pypliki do, wystarczy dodać __init__.pydo testfolderu.

Gabor
źródło
1

Jeśli masz bardziej skomplikowaną konfigurację lub nie chcesz używać from ... import *instrukcji -type, możesz zdefiniować funkcję wywoływaną suitew swoim tests.py (lub testy / __ init__.py), która zwraca instancję unittest.TestSuite.

Joel Cross
źródło
0

Myślę, że ./manage.py testpo prostu uruchamia wszystkie sztuczki testowe (w django> = 1.7).

Jeśli w organizowaniu testów chodzi o grupowanie i szyfrowanie i jesteś fanem noseużywania django nose :

python manage.py test another.test:TestCase.test_method

Jeśli znasz nos, wiesz, jak używać symboli wieloznacznych we wszystkich swoich plikach.

PS

To po prostu lepsza praktyka. Mam nadzieję, że to pomoże. Odpowiedź została zapożyczona stąd: Uruchamianie konkretnego przypadku testowego w Django, gdy Twoja aplikacja ma katalog testing

Yauhen Yakimovich
źródło
0

Mam dwa pliki. Jeden jest, tests.pya drugi jest test_api.py. Mogę je uruchomić indywidualnie, jak poniżej.

   manage.py test companies.tests
   manage.py test companies.test_api

Zobacz odpowiedź @ osa na temat konwencji nazewnictwa plików.

kta
źródło