Entfernen von Singleton-Instanzen aus dem Delphi-Projekt

8

Ich versuche mein erstes Projekt zu machen, das getestet werden kann. Und es ist erstaunlich, wie ich mein Gehirn von einigen bösartigen Programmierstilen neu verdrahten muss.

Dieser Artikel hat mich darauf aufmerksam gemacht, dass Singletons pathologische Lügner sind / p>

Ich versuche nicht, dabei radikal zu sein, aber ich bin an ein Artefakt gewöhnt, von dem ich nicht weiß, wie ich es loswerden kann

Beispiel:

%Vor%

ModelFactory ist ein Singleton, der auf seiner Unit und einem Teil der uses-Klausel dieser Unit definiert ist.

In meiner MVP-Struktur definiere ich jedes der Models, Views und Presenter in einer eigenen Einheit (1 Einheit der Klasse 1). Alle diese Einheiten stehen zur Verfügung, um den Bedürfnissen jedes Projekts gerecht zu werden. Also benutze ich es wie einen Teilekatalog, nach dem Projekt füge ich die Einheiten dem Projekt hinzu und es wird automatisch registriert und kann von den Fabriken verwendet werden.

Um das Singleton-Problem zu lösen, habe ich daran gedacht, sie in eine Framework-Klasse zu verschieben, so dass ich das Objekt an einem Punkt erstellen und dann die Abhängigkeitsinjektion verwenden kann, um das Framework-Objekt zu übergeben. Alle Fabriken und andere Umwelt-Sachen sitzen dort:

%Vor%

Meine Idee ist, die Singletons so zu entfernen, dass ich sie in einer Testeinheit verspotten kann. Mit Singletons an Ort und Stelle kann ich sie nicht leicht zum Testen entfernen.

Aber das wird mich die automatische Initialisierung jeder Einheit verlieren lassen, und darauf setze ich die Einheiten. Ich möchte nicht manuell eine Liste verfügbarer Klassen erstellen.

Gibt es eine Möglichkeit, diese Situation zu lösen?

    
Eduardo Elias 14.05.2014, 00:03
quelle

4 Antworten

4

Damit ein Komponententest ohne ein vollständiges Neuschreiben all Ihrer Singletons in Gang kommt, habe ich festgestellt, dass das Hinzufügen der Fähigkeit zu Free und ret Create die Singletons normalerweise mehr als genug ist, um Sie zu bekommen gestartet.

Angenommen, die Singletons werden in einem Initialisierungsabschnitt instanziiert (Verbieten Sie diese. Sie sind der Fluch eines Einheitentests. Gehen Sie für separate Registrierungs- und Initialisierungseinheiten.), Sie können einfach zwei Prozeduren zum Schnittstellenabschnitt hinzufügen. Setzen Sie sie zwischen bedingte Definitionen, wenn Sie nicht möchten, dass andere Einheiten in Ihrem normalen Projekt sie verwenden:

%Vor%

Verschieben Sie den Code, den Sie jetzt in Ihren Initialisierungs- und Finalisierungsabschnitten haben, in die Implementierung dieser Prozeduren und rufen Sie sie einfach bei der Initialisierung und Finalisierung auf.

%Vor%

Damit können Sie beginnen, InstantiateMySingleton und FreeMySingleton in den Setup- und Teardown-Methoden Ihrer Komponententests zu verwenden.

Alles, was Sie dann noch tun müssen, ist sicherzustellen, dass das Erstellen und Zerstören des Singletons keinen Speicherverlust verursacht und etwas ist, das tatsächlich jedes Mal mit denselben funktionalen Ergebnissen wiederholt werden kann. Eine Sache, die ich gefunden habe, um dies zu gewährleisten, besteht darin, den GUI-Runner zu verwenden und die gesamte Testsuite zweimal auszuführen (ohne natürlich die GUI zu verlassen!). Wenn Tests beim ersten Ausführen erfolgreich sind und beim zweiten Ausführen fehlschlagen, haben Sie Probleme bei der Initialisierung oder Finalisierung Ihres Singleton.

    
Marjan Venema 14.05.2014, 10:19
quelle
4

Es kommt darauf an, ob Sie die Instanz in einer anderen Klasse oder in der Factory benötigen, um die Klasse zu einem späteren Zeitpunkt zu instanziieren. Im ersten Fall können Sie die konstruierte Instanz einfach als Abhängigkeit übergeben. Im anderen Fall passiert man die Fabrik. In beiden Fällen verwenden Sie die Abhängigkeitsinjektion, anstatt sie in einer anderen Einheit nachzuschlagen ("Suchen Sie nicht nach Dingen, sondern fragen Sie nach Dingen").

Natürlich erfordert dies einen Kabelcode für die Abhängigkeit ("DI des armen Mannes") oder die Verwendung eines DI-Containers.

Dependency-Injection ist wirklich die einzige Möglichkeit, Dinge auf eine saubere Art und Weise testbar zu machen, weil Sie einfach Mocks an das SUT übergeben.

    
Stefan Glienke 14.05.2014 05:59
quelle
1

Im Allgemeinen macht Misco den Fall, dass Singletons in anderen Objekten verwendet werden (nicht). Es ist ein bisschen eine Strecke, aber man könnte eine Delphi-Einheit als ein Objekt sehen, also ist die Frage, was zu tun ist, um die Singleton-Abhängigkeit in der Einheit zu entfernen.

Die einfachste Lösung, die ich seit einiger Zeit verwende, ist den gesamten Initialisierungscode für ein give-Projekt in eine (oder mehrere) -Einheiten zu verschieben, die nur dazu dient ist die Initialisierung für Ihre Anwendung zu tun.

Was Ihre Testfälle betrifft, können Sie jetzt diese Unit auslassen und (mock) initialisieren, wie Sie wollen.

    
Lieven Keersmaekers 14.05.2014 05:06
quelle
1

Wenn ich genug aussehe, bin ich sicher, dass ich einen Artikel finden kann, der jedes Designmuster entweder als Anti-Muster oder als Inkarnation des Teufels beschreibt. Zum Beispiel ist hier ein Artikel, der das Service Locator-Muster als Anti-Pattern beschreibt:

Ссылка

Ich habe Kommentare gesehen, die Fabrikmuster als Anti-Muster beschreiben.

Ich habe in der Vergangenheit oft Singletons in Fabriken verwendet und ich habe kein Problem damit, die Adapter / Plugins / etc zu testen, die ich in Unit-Tests mit diesen Fabriken "lade". Normalerweise ist der Code in Singletons einfach und nicht etwas, was ich selbst testen würde. Der Code wird nur bei normaler Verwendung getestet. Alle Dependency Injection-Bibliotheken, die ich gesehen habe, enthalten einen Singleton für ihren globalen Container.

Wenn möglich, konfiguriere ich meine Adapter gerne in XML. Das System selbst ist dann komplett modular und einfach zu testen.

Ich sage nicht, dass die Abhängigkeitsinjektion schlecht ist. Weit davon entfernt. Ich mag das. Wenn Sie ein System von Grund auf neu erstellen, würde ich sicherlich befürworten, dass es ein guter Rahmen ist, um herum zu entwerfen, und Spring4D ist eine gute Implementierung. Ich stelle einen anderen Standpunkt vor. Ich denke, dass das Neuschreiben Ihres Systems, um zu versuchen, die Vorteile einer neueren oder anderen Technologie zu nutzen, Ihre letzte Anlaufstelle sein sollte. Es erinnert mich an den Joel-Spolsky-Artikel über die Netscape-Neufassung von Navigator ( Ссылка ).

    
Graymatter 14.05.2014 06:55
quelle

Tags und Links