Ich arbeite daran, meine Klassen mit Hilfe von Dependency Injection Unit-testbar zu machen. Aber einige dieser Klassen haben viele Clients, und ich bin noch nicht bereit, alle zu überarbeiten, um die Abhängigkeiten noch zu übergeben. Also versuche ich es allmählich zu tun; Behalten Sie die Standardabhängigkeiten vorerst bei, lassen Sie sie jedoch zum Testen außer Kraft setzen.
Ein Ansatz, den ich verfolge, besteht darin, alle "neuen" Aufrufe in ihre eigenen Methoden zu verschieben, z.
public MyObject createMyObject(args) {
return new MyObject(args);
}
Dann kann ich in meinen Unit-Tests diese Klasse einfach in Unterklassen unterteilen und die Erstellungsfunktionen überschreiben, sodass sie stattdessen gefälschte Objekte erstellen.
Ist das ein guter Ansatz? Gibt es irgendwelche Nachteile?
Ist es im Allgemeinen in Ordnung, fest codierte Abhängigkeiten zu haben, solange Sie diese zum Testen ersetzen können? Ich weiß, dass der bevorzugte Ansatz darin besteht, sie explizit im Konstruktor zu fordern, und ich möchte irgendwann dorthin gelangen. Aber ich frage mich, ob dies ein guter erster Schritt ist.
Ein Nachteil, der mir gerade aufgefallen ist: Wenn Sie echte Unterklassen haben, die Sie testen müssen, können Sie die Testunterklasse, die Sie für die übergeordnete Klasse geschrieben haben, nicht wiederverwenden. Sie müssen für jede reale Unterklasse eine Test-Unterklasse erstellen und diese muss die Erstellungsfunktionen überschreiben.
Antworten:
Dies ist ein guter Ansatz, um Ihnen den Einstieg zu erleichtern. Beachten Sie, dass es am wichtigsten ist, Ihren vorhandenen Code mit Unit-Tests abzudecken. Sobald Sie die Tests abgeschlossen haben, können Sie die Umgestaltung freier gestalten , um Ihr Design weiter zu verbessern.
Der Ausgangspunkt besteht also nicht darin, das Design elegant und glänzend zu gestalten , sondern die Codeeinheit mit den geringsten Risiken testbar zu machen . Ohne Unit-Tests müssen Sie besonders konservativ und vorsichtig sein, um den Code nicht zu beschädigen. Diese anfänglichen Änderungen können in einigen Fällen sogar dazu führen, dass der Code ungeschickter oder hässlicher aussieht. Wenn Sie jedoch die ersten Komponententests schreiben können, können Sie möglicherweise eine Umgestaltung in Richtung des von Ihnen gewünschten idealen Designs vornehmen.
Die grundlegende Arbeit, die Sie zu diesem Thema lesen sollten, besteht darin, mit Legacy-Code effektiv zu arbeiten . Es beschreibt den Trick, den Sie oben zeigen, und viele, viele weitere in mehreren Sprachen.
quelle
Die Guice-Leute empfehlen die Verwendung von
für alle Eigenschaften, anstatt nur @Inject zu ihrer Definition hinzuzufügen. Auf diese Weise können Sie sie wie normale Beans behandeln, die Sie
new
beim Testen (und beim manuellen Festlegen der Eigenschaften) und bei @Inject in der Produktion verwenden können.quelle
Wenn ich mit dieser Art von Problem konfrontiert werde, werde ich jede Abhängigkeit meiner zu testenden Klasse identifizieren und einen geschützten Konstruktor erstellen, der es mir ermöglicht, sie weiterzugeben Deklarieren von Abhängigkeiten in meinen Konstruktoren, damit ich nicht vergesse, sie in Zukunft zu instanziieren.
Meine neue prüfbare Einheitenklasse wird also 2 Konstruktoren haben:
quelle
Möglicherweise möchten Sie den Ausdruck "Getter erstellt" in Betracht ziehen, bis Sie die injizierte Abhängigkeit verwenden können.
Beispielsweise,
Auf diese Weise können Sie intern umgestalten, sodass Sie Ihr myObject durch den Getter referenzieren können. Sie müssen nie anrufen
new
. Wenn in Zukunft alle Clients so konfiguriert sind, dass sie das Einfügen von Abhängigkeiten zulassen, müssen Sie den Erstellungscode nur an einer Stelle entfernen - dem Getter. Mit dem Setter können Sie nach Bedarf Scheinobjekte injizieren.Der obige Code ist nur ein Beispiel und legt den internen Status direkt offen. Sie sollten sorgfältig prüfen, ob dieser Ansatz für Ihre Codebasis geeignet ist.
Ich würde auch empfehlen, dass Sie " Effektiv mit Legacy-Code arbeiten " lesen, der eine Fülle nützlicher Tipps enthält, um ein größeres Refactoring zum Erfolg zu führen.
quelle