Utilizando el mismo conjunto de pruebas en varias implementaciones de un interfaz del repositorio

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

Pregunta

He estado haciendo un poco de juguete de la aplicación web en C# lo largo de las líneas de Rob Connery del Asp.net MVC escaparate.

Me encuentro con que tengo un interfaz del repositorio, lo llaman IFooRepository, con los métodos, dicen

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

Y tengo tres implementaciones de este:ISqlFooRepository, IFileFooRepostory, y IMockFooRepository.

También tengo algunos de los casos de prueba.Lo que me gustaría hacer, y que no han trabajado fuera de cómo para hacer todavía, es la ejecución de los mismos casos de prueba en contra de cada uno de estos tres implementaciones, y tiene una marca de verificación verde para cada paso de la prueba en cada tipo de interfaz.

por ejemplo,

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

Quiero que este método de prueba se ejecutan tres veces, con alguna variación en el medio ambiente que le permite obtener tres diferentes tipos de repositorio.En la actualidad tengo tres cortado y pegado las clases de prueba que solo difieren en la aplicación del método auxiliar privado IFooRepository GetRepository();Obviamente, esto huele mal.

Sin embargo, yo no podemos simplemente eliminar la duplicación mediante la consolidación de la corte y pegado de los métodos, ya que ellos necesitan para estar presentes, público y marcado como prueba para la prueba que desee ejecutar.

Estoy usando el Microsoft framework de prueba, y prefieren quedarse con ella si puedo.Pero una sugerencia de cómo hacer esto, por ejemplo, MBUnit, también habría de ser de algún interés.

¿Fue útil?

Solución

Crear una clase abstracta que contiene el hormigón versiones de las pruebas y un resumen GetRepository método que devuelve IFooRepository.Crear tres clases que derivan de la clase abstracta, cada uno de los cuales implementa GetRepository en una forma que devuelve el adecuado IFooRepository aplicación.Agregue las tres clases de su suite de prueba, y usted está listo para ir.

Para ser capaz de ejecutar de forma selectiva las pruebas para algunos proveedores y a otros no, considere el uso de la MbUnit '[FixtureCategory]' atributo para la categorización de las pruebas - las categorías sugeridas son 'rápido' 'lento' 'db' 'importante' y 'sin importancia' (Los dos últimos son bromas - honesto!)

Otros consejos

En MbUnit, usted podría ser capaz de utilizar el RowTest atributo para especificar los parámetros de la prueba.

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

Si usted tiene su 3 copia y pega métodos de prueba, usted debe ser capaz de refactorizar (extracto de método) para deshacerse de la duplicación.

es decir,esto es lo que yo tenía en 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);
}

En resumen, hay tres maneras de llegar:

1) Hacer las pruebas de trazadores de líneas uno que llamar a métodos comunes (respuesta de Rick, también Hallgrim)

2) el Uso MBUnit del RowTest función para automatizar este (respuesta de Jon Limjap).Yo también uso una enumeración aquí, por ejemplo,

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

3) el Uso de una clase base, la respuesta por belugabob
He hecho una muestra basada en esta 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;
    }
}

Esto produce cuatro de pasar las pruebas en dos clases de prueba.
Beneficios de 3 son:
1) Menos código extra, menos mantenimiento
2) Menos escribir para conectar un nuevo repositorio de ser necesario - se llevaría a cabo en un solo lugar, a diferencia de los demás.

Las desventajas son:
1) Menor flexibilidad para no ejecutar una prueba en contra de un proveedor si es necesario
2) es más Difícil de leer.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top