2010-11-09 17 views
6

Bei Verwendung der Abhängigkeitsinjektion welche Abhängigkeiten injizieren Sie?Welche Abhängigkeiten sollte ich injizieren?

ich zuvor injiziert alle Abhängigkeiten, aber gefunden haben, wenn TDD tun gibt es typischerweise zwei Arten von Abhängigkeit:

  • Diejenigen, die echte externe Abhängigkeiten sind, die beispielsweise kann sich ändern ProductRepository
  • Diejenigen, die nur für die Testbarkeit existieren, z.B. Ein Teil des Verhaltens der Klasse, die für die Testbarkeit nur extrahiert und injiziert wurde

Ein Ansatz ist es, alle Abhängigkeiten wie diese

public ClassWithExternalDependency(IExternalDependency external, 
    IExtractedForTestabilityDependency internal) 
{ 
    // assign dependencies ... 
} 

aber ich habe diese Abhängigkeit aufblasen kann dazu führen, in der gefunden zu injizieren DI-Registrierung.

Ein weiterer Ansatz ist die „Testbarkeit Abhängigkeit“, wie dies

public ClassWithExternalDependency(IExternalDependency external) 
    : this (external, new ConcreteClassOfInternalDependency()) 
{} 

internal ClassWithExternalDependency(IExternalDependency external, 
    IExtractedForTestabilityDependency internal) 
{ 
    // assign dependencies ... 
} 

Dies ist mehr Mühe zu verbergen, aber scheint viel mehr Sinn zu machen. Der Nachteil ist, dass nicht alle Objekte im DI-Framework konfiguriert sind, wodurch eine "Best Practice" gebrochen wird, die ich gehört habe.

Welchen Ansatz würden Sie befürworten und warum?

Antwort

1

Ich glaube, Sie sind besser dran, alle Ihre Abhängigkeiten zu injizieren. Wenn es etwas unhandlich wird, ist das wahrscheinlich ein Hinweis darauf, dass Sie die Dinge ein wenig vereinfachen oder die Abhängigkeiten in ein anderes Objekt verschieben müssen. Den "Schmerz" deines Designs zu fühlen, während du gehst, kann wirklich aufschlussreich sein.

Wie für die Abhängigkeit in der Registrierung aufgebläht, könnten Sie eine Art von konventionellen Bindungstechnik, anstatt jede Abhängigkeit von Hand registrieren. Bei einigen IoC-Containern sind Convention-basierte Typ-Scanning-Bindungen integriert. Zum Beispiel, hier ist Teil eines Moduls I in einer Caliburn WPF-Anwendung verwenden, die Ninject verwendet:

public class AppModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IShellPresenter>().To<ShellPresenter>().InSingletonScope(); 

     BindAllResults(); 
     BindAllPresenters(); 
    } 

    /// <summary> 
    /// Automatically bind all presenters that haven't already been manually bound 
    /// </summary> 
    public void BindAllPresenters() 
    { 
     Type[] types = Assembly.GetExecutingAssembly().GetTypes(); 

     IEnumerable<Type> presenterImplementors = 
      from t in types 
      where !t.IsInterface 
      && t.Name.EndsWith("Presenter") 
      select t; 

      presenterImplementors.Run(
       implementationType => 
        { 
         if (!Kernel.GetBindings(implementationType).Any()) 
          Bind(implementationType).ToSelf(); 
        }); 
    } 

Obwohl ich Dutzende von Ergebnissen und Moderatoren haben herumlaufen, ich habe sie nicht explizit registrieren.

0

Ich werde sicherlich nicht alle Abhängigkeiten injizieren, weil aufhören sollten? Möchten Sie Ihre string Abhängigkeiten injizieren? Ich invertiere nur die Abhängigkeiten, die ich für Unit-Tests benötige. Ich möchte meine Datenbank stubben (siehe zB this example). Ich möchte das Senden von E-Mail-Nachrichten stubben. Ich möchte die Systemuhr stumm machen. Ich möchte das Schreiben in das Dateisystem stubben.

Die Sache mit der Umkehrung so vieler Abhängigkeiten wie Sie können, auch diejenigen, die Sie nicht zum Testen benötigen, ist, dass Komponententests viel schwieriger und je mehr Sie stümpfen desto weniger Sie wirklich testen, wie das System wirklich handelt . Dies macht Ihre Tests viel weniger zuverlässig. Es kompliziert auch Ihre DI-Konfiguration im Stammverzeichnis der Anwendung.

+1

Einer der Vorteile der Invertierung der Abhängigkeiten besteht darin, Einheiten isoliert testen zu können. Ich kann eine Rechnerklasse extrahieren, um sie isoliert zu testen, aber vielleicht muss sie nicht injiziert werden (siehe zweites Codebeispiel). Ich konnte es nicht in-situ testen, da es die Tests für den Client der Rechnerklasse aufblähen würde. – Alex

+1

Injizieren Sie alle injectables, neue alle newables. Ohne diese Unterscheidung würde DI verlangen, dass alle Objekte für die gesamte Dauer des Programms leben. Newables, auch Value-Typen genannt, repräsentieren inerte Daten und optional einige zugehörige transformative Verhaltensweisen (d. H. Methoden, die Werte annehmen und neue Werte zurückgeben). Injectables, auch Service/Business-Typen genannt, stellen Funktionalität und optional einen zugehörigen Programmstatus dar. Natürlich haben wir auch I/O-Typen, um den externen Zustand zu repräsentieren, z. Datei(). E/A-Typen müssen wiederverwendbar sein, sollten jedoch über abstrakte Factories erstellt werden, damit sie für Tests testweise verwendet werden können. – Jegschemesch

0

Ich würde alle meine nicht-externen Abhängigkeiten von Hand verdrahten und nur externe Abhängigkeiten 'registrieren'. Wenn ich nicht-external sage, meine ich die Objekte, die zu meiner Komponente gehören und die nur aus Gründen der einfachen Verantwortung/Testbarkeit an Schnittstellen extrahiert wurden, hätte ich niemals andere Implementierungen solcher Schnittstellen. Externe Abhängigkeiten sind Dinge wie DB-Verbindungen, Webdienste, Schnittstellen, die nicht zu meiner Komponente gehören.Ich würde sie als Schnittstellen registrieren, weil ihre Implementierungen für den Integrationstest auf Stubs umgestellt werden können. Wenn eine kleine Anzahl von Komponenten in einem DI-Container registriert ist, ist der DI-Code leichter zu lesen und frei zu blähen.

Verwandte Themen