2014-10-21 8 views
5

Ich verwende zum ersten Mal Simple Injector. In meinem .NET-Projekt leite ich testen und spöttisch zurückgegebenen Daten von einem Webdienst und Registrierung des Objekts an die Behälter wie soEinfacher Injektor, kann bestehende Registrierung nicht überschreiben

_container.Register<IWebServiceOrder>(() => mock.Object, Lifestyle.Transient); 

Dies funktioniert gut. Aber in meinen Tests möchte ich das Verhalten des Systems bei einem zweiten Aufruf an den Web-Service testen, der aktualisierte Daten enthalten wird, so dass das Mock-Objekt aktualisiert werden muss.

Standardmäßig erlaubt Simple Injector das Überschreiben bestehender Registrierungen nicht, aber die offizielle Website gibt an, dass dieses Verhalten wie unten beschrieben geändert werden kann.

https://simpleinjector.readthedocs.org/en/latest/howto.html#override-existing-registrations

container.Options.AllowOverridingRegistrations = true; 

Leider bekomme ich noch einen Fehler, wenn ich versuche, das Objekt ein zweites Mal sogar mit dem obigen Code zu registrieren.

Der Behälter nach dem ersten Aufruf zu GetInstance, GetAllInstances kann und

Alle Ideen, warum dies geschieht Verify geändert werden?

+0

Siehe [hier] (https://simpleinjector.readthedocs.org/en/latest/decisions.html#the-container-is-locked-after-the-first-call-to-resolve) warum der Container ist nach dem ersten Aufruf gesperrt, um zu lösen. – qujck

Antwort

9

Das Ersetzen einer vorhandenen Registrierung, nachdem Sie bereits mit dem Container gearbeitet haben, hat fast nie das Verhalten, das Sie erwarten würden (und dies gilt für alle DI-Bibliotheken). Aus diesem Grund ist der Simple Injector-Container gesperrt. Dies wird genauer beschrieben here (wie @qujck bereits hingewiesen).

Wenn Sie Komponententests schreiben, sollten Sie überhaupt keinen Container verwenden. Ihre Unit-Tests sollten die Klasse im Test selbst erstellen, oder Sie extrahieren, diese Logik zu einer geeigneten Factory-Methode, wie zum Beispiel:

private static MailNotifier CreateMailNotifier(
    IDeposit deposit = null, ISendMail mailSender = null, ILog logger = null) 
{ 
    return new MailNotifier(
     deposit ?? Substitute.For<IDeposit>(), 
     mailSender ?? Substitute.For<ISendMail>(), 
     logger ?? Substitute.For<ILog>()); 
} 

Diese Factory-Methode ist eine Variante zum Test Data Builder pattern.

Durch die Verwendung von optionalen Parameter zu machen, erlaubt es das Gerät zu testen es während des Tests erfordert nur die gefälschte Implementierung zu spezifizieren:

public void Notify_WithValidUser_LogsAMessage() 
{ 
    // Arrange 
    var user = new User(); 

    var logger = new FakeLogger(); 

    MailNotifier sut = CreateMailNotifier(logger: logger); 

    // Act 
    sut.Notify(user); 

    // Assert 
    Assert.AreEqual(expected: 1, actual: logger.LoggedMessages.Count); 
} 

Wenn Sie einen Container verwenden, da die Erstellung der Klasse unter Test mit der Hand zu ist schwerfällig, weist es auf ein Problem in Ihrer Testklasse hin (höchstwahrscheinlich eine Verletzung des Prinzips der einfachen Verantwortlichkeit). Vermeiden Sie die Verwendung von Tools, um Probleme in Ihrem Design zu umgehen. Ihr Code spricht zu Ihnen.

Für Integrationstests ist es jedoch viel üblicher, den Container zu verwenden, aber in diesem Fall sollten Sie einfach einen neuen Container für jeden Integrationstest erstellen. Auf diese Weise können Sie die IWebServiceOrder ohne Probleme hinzufügen oder ersetzen.

+0

Große Antwort. Unit-Tests - nein, sollte nicht DI-Container verwenden, sondern Integration Tests - ja völlig zustimmen. Ich spiele nur zu Hause mit EF6, Simple Injector und SpecFlow und das funktioniert gut - es gibt einige Dinge, die ich bei meinen Integrationstests ersetzen möchte - hauptsächlich mit DateTime arbeiten - Ich habe einen Service, um aktuelle Datetime zu bekommen.Bei der Arbeit haben wir einen Komponententest für Unity-Registrierungen, der mehr wie ein Rauchtest funktioniert, da er ungültige/unvollständige Registrierungen mit InjectionConstructor erlaubt, aber dies findet alle Probleme im Vorfeld. HINWEIS: Bei der von uns verwendeten Unity-Version gibt es keine Überprüfung. – Andez

+0

@Andrez Sie haben mit Unity alle Probleme in einem solchen Rauchtest gefunden. Sehen Sie sich einfach die [Diagnose] (https://simpleinjector.org/diagnostics) an, die Simple Injector während der Verifikation ausführt, und sagen Sie mir, ob Sie diese Art von Fehlern im Voraus mit Unity erkennen können. – Steven