Wer sollte Abhängigkeiten in einer TDD-Anwendung initialisieren?

8

Ich versuche zu lernen, wie man TDD mit spöttischen / gefälschten Objekten implementiert. Eine der Fragen, die ich habe, ist, wie man eine Abhängigkeit in einer Anwendung initialisiert, die TDD implementiert. Ein Beispiel aus diesem Artikel Beginning Mocking With Moq 3 zeigt:

public class OrderWriter
{
    private readonly IFileWriter fileWriter;

    public OrderWriter(IFileWriter fileWriter)
    {
        this.fileWriter = fileWriter;
    }

    public void WriteOrder(Order order)
    {
        fileWriter.WriteLine(String.Format("{0},{1}", order.OrderId, order.OrderTotal));
    }
}

In diesem Beispiel verwendet der Konstruktor einen IFileWriterParameter, vermutlich, weil Sie im Falle der tatsächlichen Anwendung den echten Dateischreiber und den gefälschten für den Komponententest angeben möchten. Meine Frage ist, wer in der realen Anwendung diesen Parameter liefert? Ich nehme an, es wird der Anrufer dieser Anwendung sein. Was ist, wenn es auch eine Abhängigkeit im Konstruktor gibt? Wird der Anrufercode auch dafür verantwortlich sein?

Vielleicht ist der bessere Weg, Fabrik zu verwenden. Wie würde diese Fabrik funktionieren? Und wie wird die Fabrik verteilt? Wird es wie oben beschrieben im Konstruktorparameter sein?

Louis Rhys
quelle

Antworten:

7

Was Sie suchen, ist ein IoC-Container, mit dem Sie alle Ihre Objekte beim Start der Anwendung automatisch verdrahten können. Schauen Sie sich Ninject an , es gibt ein sehr einfaches Beispiel auf der Titelseite. (Es ist auch ein gutes Produkt und ... na ja, Ninjas!)

In der Regel sollten Sie versuchen, alle Objekte der obersten Ebene (z. B. Seite in ASP.NET, Controller in MVC für ASP.NET, Formular in Winforms) direkt aus dem IoC-Container aufzulösen und ALLE Ihre Objekte zu verkabeln Abhängigkeiten durch Konstruktorinjektion. Es wird Zeiten geben, in denen Sie das Auflösen eines untergeordneten Elements erzwingen müssen - dies wird als Verwendung als Service Locator bezeichnet -, dies sollte jedoch im Allgemeinen vermieden werden, da es schwierig (aber nicht unmöglich) ist, es zu testen Erstellen Sie eine API, die für den Verbraucher verwirrend sein kann, wenn Sie es nicht sind.

ASP.NET für MVC wurde seit Version 3 speziell entwickelt, um den IoC-Container vom Rest Ihres Codes zu abstrahieren und Ihnen gleichzeitig zu ermöglichen, über den DependencyResolver automatisch in eine Klasse der obersten Ebene (Controller, Ansicht, Filter usw.) zu injizieren Klasse . Andere .NET-Frameworks erfordern etwas mehr Aufwand, aber es ist möglich, wenn Sie Google verwenden.

Zu diesem Thema gibt es ein Buch mit dem Titel Dependency Injection in .NET . Ich habe es nicht persönlich gelesen, aber ich habe gute Dinge gehört.

pdr
quelle
0

Ich habe den Ansatz gesehen, einen Standardkonstruktor hinzuzufügen, der den parametrisierten Konstruktor mit Standardinstanzen aufruft, dh "Abhängigkeitsinjektion eines armen Mannes".

public OrderWriter()
    : this(new TextFileWriter())
{
}

Der reguläre Codepfad ruft den Standardkonstruktor auf, während der Komponententest mit dem benutzerdefinierten Konstruktor initialisiert wird.

Wenn jemand die Vor- und Nachteile dieses Ansatzes erläutern könnte, würde ich es sehr schätzen.

Timo
quelle