Ich denke, Sie haben Ihre eigene Frage beantwortet. Die gleichen Dinge, die Sie zum Testen eines Web-Frameworks verwenden, gelten auch für Django, z. B. Inversion der Kontrolle und Abhängigkeitsinjektion. Sie können es in Python ziemlich einfach halten, also lassen Sie sich nicht einschüchtern oder abschalten von dem, was zum Beispiel in Spring existiert.
Warum verschieben Sie den Code nicht aus der klassenbasierten Sicht? Ihr Code wird immer noch nicht DRY sein, wenn Sie aus irgendeinem Grund die gleiche Logik an anderer Stelle benötigen. Nur weil es Django ist, bedeutet das nicht, dass gute Programmierprinzipien nicht zutreffen.
Ich würde vorschlagen, nur einige Dinge in neuen Klassen abstrahieren/Python-Module wie Dienste (als ein Konzept, nicht Django Definition von Diensten) und andere logische Abstraktionen für den Datenzugriff. Dann sind Sie unabhängig vom Request/Response-Lebenszyklus einer Django-View. Es gibt eine Tendenz von Django und Rails Entwicklern, jedes Bit der Logik direkt in das Modell oder die Ansicht zu setzen. Dies führt nur zu Gott-Klassen und Dingen, die schwer zu testen sind.
Sie können dies auch erleichtern, indem Sie Ihre Ansicht als eine leichte Abstraktion betrachten, die Dinge wie Marshalling Params (GET/POST) usw. mit dem Rest Ihres Codes behandelt und die an anderer Stelle eingekapselte Logik aufruft. IMO, wenn Sie testbaren Code möchten, 99% der Logik sollte außerhalb des Web-Kontext sein, es sei denn, es ist absolut entscheidend für den Prozess. Dies macht es auch einfacher, Dinge im Hintergrund und parallel zu betreiben.
Am Ende sollten normale Python-Module und Klassen stehen, die einfach zu testen sind, da sie keine direkten Abhängigkeiten zu HTTP haben. Wenn Sie HTTP nachahmen müssen, können Sie das Anforderungsobjekt einfach mockern. Sie haben Glück, dass die Kombination von Python/Django es leicht macht, diese Dinge als einfache dicts/kwargs auszugeben und zu verspotten.
Eine Sache, die ich mit klassenbasierten Sichten realisiert habe, ist die Verwendung mit Mixins und das Erzwingen einiger Konventionen (Rückgabe von JSON, offene Grapheigenschaften usw.), aber Verwendung der "fortgeschrittenen" klassenbasierten Sichten, die direkt Modelle benötigen wie DetailView erschweren die Dinge unnötig. Diese Ansichten sind gut für Admin-Bildschirme, aber für echte Apps helfen mehr als weh. Sie machen es schwer, Leistung zu testen und zu morden, wenn Sie keine nette, nahtlose Möglichkeit finden, Caching-Ebenen und ähnliches zu integrieren. An dieser Stelle ist es normalerweise einfach, von View oder TemplateView zu erben und damit fertig zu werden.
In Bezug auf DB Mocking speziell, erstellen Sie Ihre Mocks und gehen Sie durch Ihre Geschäftslogik. Dann spielt es keine Rolle, was Sie eingeben/ausgeben, solange es bestimmten Regeln und Schnittstellen entspricht. Sehen Sie etwas wie Mixer zum Beispiel. Sie können temporäre DBs auch während des Tests erstellen/löschen. Eine Möglichkeit besteht darin, separate Einstellungsmodule für dev/staging/production/testing usw. zu erstellen und diese abhängig von der Umgebung dynamisch zu laden. Auf diese Weise können Sie verhindern, dass Ihre Working Dev-Datenbank beim Ausführen von Komponententests beschädigt wird. Natürlich geht das mehr in eine Form des Integrationstests über, aber Sie sollten wahrscheinlich auch etwas davon machen. Die oben genannten Lösungen sind in anderen ORMs wie Hibernate üblich.
In Bezug auf die vorherige, können Sie etwas wie den folgenden Code in Ihren Einstellungen tun, um eine In-Memory-Datenbank für Komponententests zu verwenden. Schließlich obwohl, müssen Sie noch die Integrationstests gegen den tatsächlichen Datenspeichertyp, zum Beispiel MySQL
if 'test' in sys.argv:
DATABASES['default']['ENGINE'] = 'sqlite3'
prüfen; TLDR
Setzen Sie Ihre Logik außerhalb Klassenansichten in der richtigen Objekte und Module.
Verhindern Sie nicht, dass die verschiedenen gebündelten klassenbasierten Ansichten für echte Apps und jeden Anwendungsfall funktionieren. Roll deinen eigenen.
Verwenden Sie im Allgemeinen gute TDD-Prinzipien wie IOC, Übergabe der erforderlichen Parameter an Konstrukteure, lose Kopplung von Dingen, Vermeidung übermäßiger proprietärer Anforderungen (insbesondere HTTP).
- Vermeiden Sie die DB-Abhängigkeit, indem Sie Standard-Mock-Objekte erstellen (siehe # 3) und service-ähnliche Schnittstellen durchlaufen (siehe # 1).