Domanda

Ho realizzato una piccola applicazione web giocattolo in C# sulla falsariga della vetrina Asp.net MVC di Rob Connery.

Trovo di avere un'interfaccia repository, chiamala IFooRepository, con metodi, diciamo

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

E ho tre implementazioni di questo:ISqlFooRepository, IFileFooRepository e IMockFooRepository.

Ho anche alcuni casi di prova.Ciò che mi piacerebbe fare, e non ho ancora capito come farlo, è eseguire gli stessi casi di test su ciascuna di queste tre implementazioni e avere un segno di spunta verde per ogni test superato su ciascun tipo di interfaccia.

per esempio.

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

Voglio che questo metodo di test venga eseguito tre volte, con qualche variazione nell'ambiente che gli consenta di ottenere tre diversi tipi di repository.Al momento ho tre classi di test taglia e incolla che differiscono solo nell'implementazione del metodo di supporto privato IFooRepository GetRepository();Ovviamente, questo è puzzolente.

Tuttavia, non posso semplicemente rimuovere la duplicazione consolidando i metodi taglia e incolla, poiché devono essere presenti, pubblici e contrassegnati come test affinché il test venga eseguito.

Sto utilizzando il framework di test Microsoft e, se possibile, preferirei mantenerlo.Ma anche un suggerimento su come farlo, ad esempio, in MBUnit sarebbe di un certo interesse.

È stato utile?

Soluzione

Crea una classe astratta che contenga versioni concrete dei test e un metodo GetRepository astratto che restituisca IFooRepository.Crea tre classi che derivano dalla classe astratta, ognuna delle quali implementa GetRepository in modo da restituire l'implementazione IFooRepository appropriata.Aggiungi tutte e tre le classi alla tua suite di test e sei pronto per partire.

Per poter eseguire selettivamente i test per alcuni fornitori e non per altri, considera l'utilizzo dell'attributo MbUnit '[FixtureCategory]' per classificare i tuoi test: le categorie suggerite sono 'veloce' 'lento' 'db' 'importante' e 'non importante' ( Gli ultimi due sono scherzi - onesto!)

Altri suggerimenti

In MbUnit, potresti essere in grado di utilizzare l'attributo RowTest per specificare i parametri del tuo test.

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

Se hai i tuoi 3 metodi di test copia e incolla, dovresti essere in grado di rifattorizzarli (metodo di estrazione) per eliminare la duplicazione.

cioè.questo è quello che avevo in mente:

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);
}

Per riassumere, ci sono tre strade da percorrere:

1) Rendi i test una battuta che richiami a metodi comuni (risposta di Rick, anche Hallgrim)

2) Utilizza la funzione RowTest di MBUnit per automatizzare questa operazione (risposta di Jon Limjap).Vorrei anche usare un'enumerazione qui, ad es.

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

3) Usa una classe base, rispondi belugabob
Ho realizzato un campione basato su questa idea

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;
    }
}

Ciò produce quattro test di superamento in due classi di test.
I vantaggi di 3 sono:
1) Minimo codice aggiuntivo, minima manutenzione
2) Almeno digitando per collegare un nuovo repository, se necessario: verrebbe fatto in un posto, a differenza degli altri.

Gli aspetti negativi sono:
1) Meno flessibilità nel non eseguire un test contro un fornitore, se necessario
2) Più difficile da leggere.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top