Wie verteile ich Django-Unit-Tests auf mehrere Dateien?

126
  • Ich habe eine Python-Django-Anwendung
  • Ich verwende das Unit-Testing-Framework
  • Die Tests sind in der Datei "tests.py" im Modulverzeichnis angeordnet
  • Ich führe die Tests über aus ./manage.py test app

Jetzt..

  • Die tests.pyDatei wird ziemlich groß / komplex / chaotisch
  • Ich möchte tests.pyin kleinere Testsammlungen aufteilen ...

Wie?

John Mee
quelle

Antworten:

47

Das Verhalten hat sich in Django 1.6 geändert, sodass kein Paket mehr erstellt werden muss. Benennen Sie einfach Ihre Dateien test*.py.

Aus der Django 1.7-Dokumentation

Wenn Sie Ihre Tests ausführen, besteht das Standardverhalten des Testdienstprogramms darin, alle Testfälle (dh Unterklassen von unittest.TestCase) in einer Datei zu finden, deren Name mit test beginnt. Erstellen Sie automatisch eine Testsuite aus diesen Testfällen. und führen Sie diese Suite aus.

Aus der Django 1.6-Dokumentation ,

Die Testerkennung basiert auf der integrierten Testerkennung des unittest-Moduls. Standardmäßig werden Tests in jeder Datei mit dem Namen "test * .py" im aktuellen Arbeitsverzeichnis erkannt.

Vorheriges Verhalten aus der Django 1.5-Dokumentation :

Wenn Sie Ihre Tests ausführen, besteht das Standardverhalten des Testdienstprogramms darin, alle Testfälle (dh Unterklassen von unittest.TestCase) in models.py und tests.py zu finden und automatisch eine Testsuite aus diesen Testfällen zu erstellen. und führen Sie diese Suite aus.

Es gibt eine zweite Möglichkeit, die Testsuite für ein Modul zu definieren: Wenn Sie eine Funktion namens suite () in models.py oder tests.py definieren, verwendet der Django-Testläufer diese Funktion, um die Testsuite für dieses Modul zu erstellen. Dies folgt der vorgeschlagenen Organisation für Unit-Tests. Weitere Informationen zum Erstellen einer komplexen Testsuite finden Sie in der Python-Dokumentation.

osa
quelle
4
In Django 2.6 entdeckt es nicht wirklich etwas ...
LtWorf
2
Derzeit verwende ich Django 1.10 und wollte alle meine test*.pyDateien in einem Ordner ablegen, der aufgerufen wird tests, um den Ordner sauber zu halten. Dies ist möglich, aber Sie müssen es ausführen ./manage.py test app.testsund alle relativen Importe müssen eine Ebene from .modelshöher werden ( werden from ..models).
Scott Stevens
123

Beachten Sie, dass dieser Ansatz ab Django 1.6 nicht mehr gültig ist (siehe diesen Beitrag) .

Sie können testsOrdner mit ___init___.pyinnen erstellen (so dass es ein Paket wird). Anschließend fügen Sie dort Ihre Split-Test-PY-Dateien hinzu und importieren alle in ___init___.py.

Dh: Ersetzen Sie die test.pyDatei durch ein Modul, das wie die Datei aussieht und funktioniert:

Erstellen Sie ein testsVerzeichnis unter der betreffenden App

App
app \ models.py
app \ views.py
App \ Tests
app \ tests \ __ init__.py
app \ tests \ bananas.py
app \ tests \ apples.py

Importieren Sie die Submodule in app\tests\__init__.py:

from bananas import *
from apples import *

Jetzt können Sie ./manage.py so verwenden, als wären sie alle in einer einzigen Datei:

./manage.py test app.some_test_in_bananas
Tomasz Zieliński
quelle
1
Doh. Sie wollten unter der Anwendung, die ich teste, ein Testmodul erstellen. Keine neue Anwendung namens Tests. Ich verstehe es jetzt. Genial. Vielen Dank!
John Mee
@ John: Ich kann meine Antwort nicht mehr erkennen! :-) Aber Sie haben völlig Recht, dass es zu vage war, auch wenn es richtig ist - Ihre Beispiele machen es entgegen meiner ursprünglichen Formulierung klar.
Tomasz Zieliński
2
@Tomasz .. Deine Worte sind immer noch da - ganz intakt. Ich habe es nur ein wenig ausgearbeitet, seit du mich auf den richtigen Weg gebracht hast.
John Mee
@ John: Ich war überhaupt nicht böse, wenn du das meinst :) Es war einfach lustig, meine eigene Antwort in einer etwas anderen Form zu sehen
Tomasz Zieliński
4
@jMyles, wenn du mit "normalem Django-Testläufer" meinst, python manage.py test myappdann funktioniert diese Antwort tatsächlich einwandfrei . (habe es gerade versucht)
Kirk Woll
27

Die Antwort von Tomasz ist richtig. Es kann jedoch mühsam werden, sicherzustellen, dass die Importe __init__.pyIhrer Dateistruktur entsprechen.

Um alle Tests im Ordner automatisch zu erkennen , können Sie Folgendes hinzufügen __init__.py:

import unittest

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

Auf diese Weise können Sie ./manage.py test appnamebestimmte Tests ausführen, jedoch nicht ausführen . Dazu können Sie diesen Code verwenden (auch in __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__)

Jetzt können Sie alle Ihre Tests über manage.py test appoder bestimmte Tests über ausführenmanage.py test app.TestApples

Bryce Drennan
quelle
Wo platzierst du das zweite Stück?
Rh0dium
Beide Stücke gehen in__init__.py
Bryce Drennan
Beachten Sie, dass, wenn einer Ihrer Testpaketnamen mit den Modulnamen der obersten Ebene übereinstimmt, die während des Testlaufs importiert werden, das pkgutil-Snippet dazu führt, dass der Import fehlschlägt, da die Tests als hinzugefügt werden sys.modules[packagename]. Eine schnelle Problemumgehung ist für delalle Probleme, die nach den oben genannten Problemen auftreten. (Oder Sie könnten Ihre Ordner umbenennen;))
Paul Fenney
Das ist großartig, aber ich bin auf einen Fehler gestoßen, bei dem beim Ausführen eines Tests auf App-Ebene ( python manage.py test appName) das zweite Codebit einen Fehler auslöst, der besagt, dass __path__nicht verfügbar war. Ich habe es vermieden, indem ich das zweite Snippet in einen if '__path__' in locals():Scheck eingewickelt habe, was den Trick getan hat. Danke für die Antwort!
Alukach
1
+1 Dies stellt auch sicher, dass die Init- Datei den gängigen Codierungsstandards entspricht, dh keine * oder nicht verwendeten Importe hat
Martin B.
13

Machen Sie einfach Ihre Verzeichnisstruktur wie folgt:

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

Und python manage.py test myappwird wie erwartet funktionieren.

Spiderlama
quelle
2

In init muss nichts codiert werden. Erstellen Sie einfach ein Unterverzeichnis in Ihrer App. Die einzige Voraussetzung ist , es nicht Tests zu nennen. * Zum Beispiel

app/
app/__init_.py
app/serializers.py
app/testing/
app/testing/__init__.py
app/testing/tests_serializers.py
MaxBlax360
quelle
1
Warum kann man es nicht etwas nennen, das mit "Tests" beginnt?
Serp C
Ich verwende diese Antwort mit Django 1.11.4. Gründe für die Verwendung: (1) Die Datei "app / testing / __ init__.py" bleibt leer und (2) Der Befehl bleibt die grundlegende "python manage.py test app"
rprasad
2

Mit Django 2.2 könnte eine einfache und ziemlich gute Lösung darin bestehen, einen testOrdner in einer App zu erstellen , und Sie können Ihre zugehörigen test_...pyDateien ablegen, indem Sie sie einfach __init__.pydem testOrdner hinzufügen .

Gabor
quelle
1

Wenn Sie ein komplizierteres Setup haben oder keine from ... import *Anweisungen vom Typ -type verwenden möchten , können Sie eine Funktion definieren, die suitein Ihrer Datei tests.py (oder tests / __ init__.py) aufgerufen wird und eine Instanz von zurückgibt unittest.TestSuite.

Joel Cross
quelle
0

Ich denke, es führt ./manage.py testeinfach alle Testtricks aus (in django> = 1.7).

Wenn Ihre Organisation Tests geht es um die Gruppierung und Rosinen herauszupicken und Sie sind Fan von noseVerwendung django Nase :

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

Wenn Sie Nase kennen, dann wissen Sie, wie man über alle Ihre Dateien viel besser "Wildcard" macht.

PS

Es ist nur eine bessere Praxis. Hoffentlich hilft das. Die Antwort wurde von hier ausgeliehen: Ausführen eines bestimmten Testfalls in Django, wenn Ihre App über ein Testverzeichnis verfügt

Yauhen Yakimovich
quelle
0

Ich habe zwei Dateien. Einer ist tests.pyund ein anderer ist test_api.py. Ich kann diese einzeln wie unten ausführen.

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

Lesen Sie die Antwort von @ osa zur Dateinamenskonvention.

kta
quelle