Unter Verwendung der gleichen Testreihe auf verschiedenen Implementierungen eines Endlagers Schnittstelle

StackOverflow https://stackoverflow.com/questions/81317

Frage

Ich habe nach dem Vorbild von Rob Connery Asp.net MVC Storefront eine kleine Spielzeug Web-Anwendung in C # worden zu machen.

Ich finde, dass ich ein Repository-Schnittstelle haben, rufen Sie es IFooRepository, mit Methoden, sagen

IQueryable<Foo> GetFoo();
void PersistFoo(Foo foo);

Und ich habe drei Implementierungen dieser. ISqlFooRepository, IFileFooRepostory und IMockFooRepository

Ich habe auch einige Testfälle. Was ich möchte, tun und nicht gearbeitet haben, wie noch zu tun ist, ist die gleiche Testfälle gegen jede dieser drei Implementierungen laufen, und für jeden Testdurchlauf auf jeden Schnittstellentyp ein grünes Häkchen haben.

z.

[TestMethod]
Public void GetFoo_NotNull_Test()
{
   IFooRepository repository = GetRepository();
   var results = repository. GetFoo();
   Assert.IsNotNull(results);
}

Ich mag diese Testmethode dreimal ausgeführt werden, mit einem gewissen Variation in der Umgebung, die es drei verschiedene Arten von Repository erhalten kann. Derzeit habe ich drei eingeschnittenen und klebte Testklassen, die nur bei der Umsetzung der privaten Hilfsmethode IFooRepository GetRepository () unterscheiden; Offensichtlich ist dies muffig.

Allerdings kann ich nicht nur Vervielfältigung entfernen, indem die geschnittenen und klebte Methoden zu konsolidieren, da sie als Test vorhanden, öffentlichen und markiert sein müssen für den Test auszuführen.

Ich bin mit dem Microsoft-Test-Framework, und würde es vorziehen, mit ihm zu bleiben, wenn ich kann. Aber ein Vorschlag, wie dies zu tun in, sagen wir, MBUnit wäre auch von Interesse sein.

War es hilfreich?

Lösung

Erstellen Sie eine abstrakte Klasse, die konkrete Versionen der Tests enthält und eine abstrakte GetRepository Methode, die IFooRepository zurückgibt. Erstellen Sie drei Klassen, die von der abstrakten Klasse abgeleitet werden, von denen jede GetRepository in einer Weise implementiert, die die entsprechende IFooRepository Implementierung zurückgibt. In allen drei Klassen auf Ihre Test-Suite, und Sie sind bereit zu gehen.

Lage sein, selektiv die Tests für einige Anbieter und andere nicht ausführen, sollten Sie die MbUnit mit ‚[FixtureCategory]‘ Attribut Ihre Tests zu kategorisieren - vorgeschlagenen Kategorien sind ‚quick‘ ‚langsam‘ ‚db‘ ‚wichtig‘ und ' unwichtig‘(Die letzten beiden Witze sind - ehrlich)

Andere Tipps

In MbUnit, könnten Sie in der Lage sein, das RowTest Attribut verwenden Parameter auf Ihrem Test angeben.

[RowTest]
[Row(new ThisRepository())]
[Row(new ThatRepository())]
Public void GetFoo_NotNull_Test(IFooRepository repository)
{
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

Wenn Sie Ihre 3 Kopieren und Einfügen Testmethoden haben, sollten Sie in der Lage sein, Refactoring (Extrakt-Methode) es loszuwerden, die Doppelarbeit zu erhalten.

d. das ist, was ich im Sinn hatte:

private IRepository GetRepository(RepositoryType repositoryType)
{
    switch (repositoryType)
    {   
          case RepositoryType.Sql:
          // return a SQL repository
          case RepositoryType.Mock:
          // return a mock repository
          // etc
    }
}

private void TestGetFooNotNull(RepositoryType repositoryType)
{
   IFooRepository repository = GetRepository(repositoryType);
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

[TestMethod]
public void GetFoo_NotNull_Sql()
{
   this.TestGetFooNotNull(RepositoryType.Sql);
}

[TestMethod]
public void GetFoo_NotNull_File()
{
   this.TestGetFooNotNull(RepositoryType.File);
}

[TestMethod]
public void GetFoo_NotNull_Mock()
{
   this.TestGetFooNotNull(RepositoryType.Mock);
}
[TestMethod]
public void GetFoo_NotNull_Test_ForFile()
{   
   GetFoo_NotNull(new FileRepository().GetRepository());
}

[TestMethod]
public void GetFoo_NotNull_Test_ForSql()
{   
   GetFoo_NotNull(new SqlRepository().GetRepository());
}


private void GetFoo_NotNull(IFooRepository repository)
{
  var results = repository. GetFoo();   
  Assert.IsNotNull(results);
}

Um es zusammenzufassen, gibt es drei Wege zu gehen:

1) Stellen Sie die Tests Einzeiler, die von Rick gängigen Methoden (Antwort ruft nach unten, auch Hallgrim)

2) Verwenden Sie MBUnit die RowTest Merkmal diese (Antwort von Jon Limjap) zu automatisieren. Ich würde auch eine ENUM hier verwenden, z.

[RowTest]
[Row(RepositoryType.Sql)]
[Row(RepositoryType.Mock)]
public void TestGetFooNotNull(RepositoryType repositoryType)
{
   IFooRepository repository = GetRepository(repositoryType);
   var results = repository.GetFoo();
   Assert.IsNotNull(results);
}

3) Verwenden Sie eine Basisklasse, Antwort von belugabob
Ich habe eine Probe auf der Basis dieser Idee gemacht

public abstract class TestBase
{
    protected int foo = 0;

    [TestMethod]
    public void TestUnderTen()
    {
        Assert.IsTrue(foo < 10);
    }

    [TestMethod]
    public void TestOver2()
    {
        Assert.IsTrue(foo > 2);
    }
}

[TestClass]
public class TestA: TestBase
{
    public TestA()
    {
        foo = 4;
    }
}

[TestClass]
public class TestB: TestBase
{
    public TestB()
    {
        foo = 6;
    }
}

Dies erzeugt vier bestandene Tests in zwei Testklassen.
Upsides von 3:
1) Die am wenigsten zusätzlicher Code, am wenigsten Wartung
2) Die am wenigsten eingeben ein neues Repository stecken, wenn es sein muss -. Es wäre an einem Ort durchgeführt werden, im Gegensatz zu dem anderen

Die Nachteile sind:
1) Weniger Flexibilität keinen Test gegen einen Anbieter ausgeführt werden, wenn Bedarf
werden 2) schwerer zu lesen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top