2017-02-21 3 views
1

Ich habe Array-basierte Stack-Datenstruktur zusammen mit entsprechenden Komponententests implementiert. Dieser Stack implementiert meine IStack-Schnittstelle. Also im Moment sieht mein UT Klasse etwas wie folgt aus:Dependency Injection in Komponententests

[TestClass] 
public class Stack_ArrayBased_Tests 
{  
    //check against empty collection 
    [TestMethod] 
    public void IsEmpty_NoElements() 
    { 
     var myStack = new Stack_ArrayBased_Example1(10); 

     var exp = true; 
     var act = myStack.IsEmpty(); 
     Assert.AreEqual(exp, act); 
    } 

Nun, ich bin über verlinkte Liste basiert Stapel zu implementieren. Dieser Stack erbt von derselben IStack-Schnittstelle.

Ich möchte Unit-Test auch die verkettete Liste Stack. Da beide von derselben Schnittstelle erben, sollte ich in der Lage sein, den bereits implementierten Komponententest zu nutzen, um unnötige Codeverdopplung zu vermeiden.

Was wäre der beste Weg, um zwei separate Komponententestklassen zu erstellen, eine für Array-basierten Stack und eine andere für Linked List-basierte Stacks, die dieselben Unit-Test-Methoden verwenden würden? Ich nehme an, Dependency Injection wäre eine Antwort, aber wie würde ich das machen?

+0

Wie bei jeder anderen Codebasis verwendet werden Sie Code, der gehört Refactoring sollen beide Szenarien in eine eigene Klasse, so dass sie in verschiedenen Anwendungsfällen verwendet werden kann. Wenn Sie also bereits eine Implementierung für Testfall 1 * haben, refaktorieren Sie das Verhalten in eine eigene Klasse und verwenden Instanzen in beiden Tests. – HimBromBeere

Antwort

2

Sie können die Logik in einer anderen Methode trennen.

[TestMethod] 
public void IsEmpty_NoElements_ArrayBased() 
{ 
    var myStack = new Stack_ArrayBased_Example1(10); 
    IsEmpty_NoElements(myStack) 
} 

[TestMethod] 
public void IsEmpty_NoElements_LinkedListBased() 
{ 
    var myStack = new Stack_LinkedListBased_Example1(10); 
    IsEmpty_NoElements(myStack) 
} 

public void IsEmpty_NoElements(IStack myStack) 
{ 
    var exp = true; 
    var act = myStack.IsEmpty(); 
    Assert.AreEqual(exp, act); 
} 
4

Die Abhängigkeitsinjektion ist niemals die Antwort, wenn es um Tests geht.

Sie testen keine Abstraktionen, das ist unmöglich, Sie testen konkrete Implementierungen. Sie können jedoch Abstraktionen, Interfaces, abstrakte Klassen vortäuschen.

Sie können eine Klasse mit dem einzigen Zweck erstellen, Code wiederzuverwenden, und Sie nennen diese Klasse von Ihren Testmethoden, das ist in Ordnung und völlig machbar.

Sie benötigen noch zwei Testklassen, eine für jede Ihrer konkreten Implementierungen, und rufen diese neue Klasse, die Sie erstellt haben, auf. Dies vermeidet eine Code-Duplizierung.

0

Sagen wir folgende

public interface IStack 
{ 
    bool IsEmpty { get; } 
} 

public class StackImpl1 : IStack 
{ 
    public StackImpl1(int size) 
    { 
    IsEmpty = true; 
    } 

    public bool IsEmpty { get; } 
} 

public class StackImpl2 : IStack 
{ 

    public StackImpl2(int size) 
    { 
    IsEmpty = true; 
    } 

    public bool IsEmpty { get; } 
} 

haben, und wir wollen den IsEmpty_OnCreation() Test aus dem OP implementieren. Wir können einen allgemeinen Test machen und mehrere Invoker hinzufügen (einen für jede zu testende Implementierung). Das Problem ist Skalierung.

Für jedes neue Stück Funktionalität wir

1), um die Testimplementierung
2) eine Aufrufer für jede Implementierung getestet werden hinzufügen müssen getestet werden.

Für jede neue Implementierung, die wir vorstellen, müssen wir für jeden vorhandenen Test einen Invoker hinzufügen.

Es ist möglich, Vererbung zu verwenden die meiste Arbeit zu tun für uns

public abstract class StackTest 
{ 
    protected abstract IStack Create(int size); 

    [TestMethod] 
    public void IsEmpty_NoElements() 
    { 
    var myStack = Create(10); 

    var exp = true; 
    var act = myStack.IsEmpty; 
    Assert.AreEqual(exp, act); 

    } 
} 

[TestClass] 
public class StackImp1Fixture : StackTest 
{ 
    protected override IStack Create(int size) 
    { 
    return new StackImpl1(size); 
    } 
} 

[TestClass] 
public class StackImp2Fixture : StackTest 
{ 
    protected override IStack Create(int size) 
    { 
    return new StackImpl2(size); 
    } 
} 

Die Tests in jeder abgeleiteten Leuchte erzeugt werden.

Wenn wir einen neuen Test hinzufügen möchten, fügen wir ihn zur Klasse StackTest hinzu und er wird automatisch in jedes abgeleitete Fixture aufgenommen.

Wenn wir eine dritte Implementierung von IStack, fügen wir einfach eine neue Testvorrichtung aus StackTest Ableiten und Überschreiben der Methode erstellen.

Hinweis:
Wenn die Klassen im Test Standardkonstruktoren haben, kann die gleiche Form mit einem generischen StackTest als

public class GenStackTest<TStack> where TStack : IStack, new() 
{ 

    [TestMethod] 
    public void IsEmpty_NoElements() 
    { 
    var myStack = new TStack(); 

    var exp = true; 
    var act = myStack.IsEmpty; 
    Assert.AreEqual(exp, act); 

    } 
} 

[TestClass] 
public class GenStack1Fixture : GenStackTest<StackImpl1> 
{ 
} 

[TestClass] 
public class GenStack2Fixture : GenStackTest<StackImpl2> 
{ 
}