Ich habe also den Google-Testblog gelesen und behauptet, dass der globale Status schlecht ist und es schwierig ist, Tests zu schreiben. Ich glaube es - mein Code ist momentan schwer zu testen. Wie vermeide ich den globalen Zustand?
Die größten Dinge, die ich global state (so wie ich es verstehe) nutzen, sind die Verwaltung wichtiger Informationen zwischen unseren Entwicklungs-, Akzeptanz- und Produktionsumgebungen. Zum Beispiel habe ich eine statische Klasse namens "Globals" mit einem statischen Member namens "DBConnectionString". Wenn die Anwendung geladen wird, ermittelt sie, welche Verbindungszeichenfolge geladen werden soll, und füllt Globals.DBConnectionString auf. Ich lade Dateipfade, Servernamen und andere Informationen in der Globals-Klasse.
Einige meiner Funktionen beruhen auf den globalen Variablen. Also, wenn ich meine Funktionen teste, muss ich daran denken, bestimmte Globals zuerst zu setzen, sonst versagen die Tests. Ich möchte das vermeiden.
Gibt es eine gute Möglichkeit, Zustandsinformationen zu verwalten? (Oder verstehe ich den globalen Zustand falsch?)
Abhängigkeitsinjektion ist, was Sie suchen. Anstatt diese Funktionen auszulöschen und nach ihren Abhängigkeiten zu suchen, injizieren Sie die Abhängigkeiten in die Funktionen. Das heißt, wenn Sie die Funktionen aufrufen, übergeben Sie die gewünschten Daten an sie. Auf diese Weise ist es einfach, ein Test-Framework um eine Klasse zu legen, da Sie einfach Mock-Objekte einfügen können.
Es ist schwierig, einige globale Zustände zu vermeiden, aber der beste Weg, dies zu tun, ist die Verwendung von Factory-Klassen auf der höchsten Ebene Ihrer Anwendung, und alles unter dieser obersten Ebene basiert auf der Abhängigkeitsinjektion.
Zwei Hauptvorteile: Erstens ist das Testen viel einfacher und zweitens ist Ihre Anwendung viel lockerer gekoppelt. Sie verlassen sich darauf, dass Sie in der Lage sind, gegen die Schnittstelle einer Klasse statt ihrer Implementierung zu programmieren.
Denken Sie daran, wenn Ihre Tests tatsächliche Ressourcen wie Datenbanken oder Dateisysteme betreffen, dann sind es Integrationstests und nicht Unit-Tests . Integrationstests erfordern einige vorbereitende Einstellungen, während Komponententests unabhängig voneinander ausgeführt werden können.
Sie könnten in die Verwendung eines Dependency-Injection-Frameworks wie Castle Windsor schauen, aber für einfache Fälle können Sie vielleicht einen Ansatz in der Mitte der Straße wählen, wie zum Beispiel:
%Vor%In Wirklichkeit würden Sie höchstwahrscheinlich von Konfigurationsdateien in Ihrer Implementierung lesen. Wenn Sie dafür bereit sind, ist ein vollständiges DI-Framework mit austauschbaren Konfigurationen der richtige Weg, aber ich denke, das ist zumindest besser als die Verwendung von Globals.ConnectionString.
Tolle erste Frage.
Die kurze Antwort: Stellen Sie sicher, dass Ihre Anwendung eine Funktion von ALLEN Eingaben (einschließlich impliziter) bis zu ihren Ausgaben ist.
Das Problem, das Sie beschreiben, erscheint nicht als globaler Zustand. Zumindest kein veränderbarer Zustand. Was Sie beschreiben, scheint eher das zu sein, was oft als "Konfigurationsproblem" bezeichnet wird, und es gibt eine Reihe von Lösungen. Wenn Sie Java verwenden, sollten Sie in leichtgewichtige Injection-Frameworks wie Guice schauen. In Scala wird dies normalerweise mit implicits gelöst. In einigen Sprachen können Sie ein anderes Programm laden, um Ihr Programm zur Laufzeit zu konfigurieren. So haben wir Server konfiguriert, die in Smalltalk geschrieben sind, und ich benutze einen in Haskell geschriebenen Window-Manager namens Xmonad, dessen Konfigurationsdatei nur ein anderes Haskell-Programm ist.
Ein Beispiel für die Abhängigkeitsinjektion in einer MVC-Einstellung lautet:
index.php
%Vor%container.php
%Vor%...
%Vor%index.php fährt hier fort:
%Vor%Und da haben Sie es, der Controller hängt von einem Dienstschichtobjekt ab, von dem es abhängt Ein Dao - Objekt (Datenzugriffsobjekt), das von einem Datenbankobjekt abhängig ist, hängt von der Datenbanktreiber, Name usw.
Tags und Links testing state global global-state