Verwenden von IoC für Unit-Tests

97

Wie kann ein IoC-Container für Unit-Tests verwendet werden? Ist es nützlich, Mocks in einer riesigen Lösung (über 50 Projekte) mit IoC zu verwalten? Irgendwelche Erfahrungen? Gibt es C # -Bibliotheken, die sich gut für Unit-Tests eignen?

Crauscher
quelle
7
@ Mark Seemann wäre zu bescheiden, um darauf hinzuweisen, aber wenn Sie an dieser Frage interessiert sind, sollten Sie zumindest AutoFixture
Ruben Bartelink
1
Es gibt ein gutes Gespräch über die Beziehung zwischen DI und Verspottung von Vimeo durch Miguel Castro: vimeo.com/68390510
GregC

Antworten:

131

Im Allgemeinen sollte ein DI-Container für Unit-Tests nicht erforderlich sein, da es bei Unit-Tests nur darum geht, die Verantwortlichkeiten zu trennen.

Stellen Sie sich eine Klasse vor, die Constructor Injection verwendet

public MyClass(IMyDependency dep) { }

In Ihrer gesamten Anwendung ist möglicherweise ein riesiges Abhängigkeitsdiagramm verborgen IMyDependency, aber in einem Komponententest reduzieren Sie alles auf ein einziges Testdoppel .

Sie können dynamische Mocks wie Moq oder RhinoMocks verwenden, um das Test Double zu generieren, dies ist jedoch nicht erforderlich.

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

In einigen Fällen kann es hilfreich sein , einen automatisch verspotteten Container zu haben, aber Sie müssen nicht denselben DI-Container verwenden, den die Produktionsanwendung verwendet.

Mark Seemann
quelle
13
vereinbart ... es sei denn, ein Testziel hat einen IoC-Container als Abhängigkeit, Ihre Tests sollten diese nicht benötigen ... Sie werden den größten Teil des Objektdiagramms entfernen, wenn Sie Ihre Komponententests durchführen.
Anderson Imes
4
@ Mark Seemann Das macht Sinn ... Aber was ist mit Integrationstests? Dh ich habe mit UI-Tests herumgespielt und war mit einer Situation konfrontiert, in der ich die Kompositionswurzel teilen musste. Irgendwelche Kommentare?
Arnis Lapsa
5
@Arnis L.: Für Integrationstests ist es weniger wichtig. Sie können einen DI-Container verwenden, um die Komponenten zu verkabeln. In diesem Fall benötigen Sie wahrscheinlich eine andere Konfiguration für den Container als in der vollständigen Anwendung - es sei denn, Sie führen in diesem Fall einen subkutanen Test oder einen vollständigen Systemtest durch Sie können die Konfiguration des Containers durch die Anwendung wiederverwenden.
Mark Seemann
siehe
18

Wie kann ein Ioc-Container für Unit-Tests verwendet werden?

IoC wird Programmierparadigmen durchsetzen, die das isolierte Testen von Einheiten (dh das Verwenden von Mocks) erleichtern: Verwendung von Schnittstellen, keine neuen (), keine Singletons ...

Die Verwendung des IoC-Containers zum Testen ist jedoch nicht unbedingt erforderlich. Er bietet lediglich einige Funktionen, z. B. das Einspritzen von Mocks, kann jedoch manuell durchgeführt werden.

Ist es nützlich, Mocks in einer riesigen Lösung (über 50 Projekte) mit IoC zu verwalten?

Ich bin mir nicht sicher, was Sie unter der Verwaltung von Mocks mit IoC verstehen. Wie auch immer, IoC-Container können normalerweise mehr als nur Mocks injizieren, wenn es um Tests geht. Und wenn Sie eine anständige IDE-Unterstützung haben, die Refactoring ermöglicht, warum nicht?

Irgendwelche Erfahrungen?

Ja, für eine große Lösung benötigen Sie mehr denn je eine nicht fehleranfällige und Refactoring-nachteilige Lösung (dh entweder über einen typsicheren IoC-Container oder eine gute IDE-Unterstützung).

Pascal Thivent
quelle
17

In meinen Tests verwende ich häufig einen IoC-Container. Zugegeben, es handelt sich nicht um "Unit-Tests" im reinen Sinne. IMO Sie sind eher BDDish und erleichtern das Refactoring. Tests sind da, um Ihnen das Vertrauen in Refactor zu geben. Schlecht geschriebene Tests können wie das Eingießen von Zement in Ihren Code sein.

Folgendes berücksichtigen:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

Beim Hinzufügen eines Bildes zur Galerie passieren verschiedene Dinge. Die Bildgröße wird geändert, eine Miniaturansicht wird erstellt und die Dateien werden auf AmazonS3 gespeichert. Durch die Verwendung eines Containers kann ich einfacher nur das Verhalten isolieren, das ich testen möchte. In diesem Fall handelt es sich um den persistierenden Teil.

Eine Auto-Mocking-Container-Erweiterung ist praktisch, wenn Sie diese Technik verwenden: http://www.agileatwork.com/auto-mocking-unity-container-extension/

Mike Valenty
quelle
8
+1 für den Satz "wie Zement in Ihren Code gießen". Ich habe die ganze Zeit damit angefangen.
Andrew Shepherd
2

Durch die Verwendung von Containern mit der Fähigkeit, nicht registrierte / unbekannte Dienste wie SimpleInjector aufzulösen , kann DryIoc (seine Mine) Mocks für noch nicht implementierte Schnittstellen zurückgeben.

Dies bedeutet, dass Sie mit der Entwicklung mit der ersten einfachen Implementierung und ihren verspotteten Abhängigkeiten beginnen und diese im weiteren Verlauf durch echte ersetzen können.

Dadhi
quelle