2010-08-31 18 views
11

Así que, básicamente, tengo un objeto de dominio y un repositorio genérico que puede hacer operaciones CRUD con ese objeto.¿Cómo puedo crear un Test Base genérico con NUnit del que puedo heredar y realizar pruebas desde la ejecución base?

public interface IBaseRepository<T> where T : BaseEntity 
{ 
    void Add(T entity); 
    void Remove(T entity); 
    T ById(int id); 
    IEnumerable<T> All(); 
} 

Así que tengo varias implementaciones de esta interfaz, una para cada objeto de dominio.

me gustaría escribir algunas pruebas de integración (usando nunit) y por eso pensé que había que hacer una BaseRepositoryTest - como esto:

public abstract class BaseRepositoryTests<T> where T : BaseEntity 
{ 
    public abstract IBaseRepository<T> GetRepository(); 
    public abstract T GetTestEntity(); 

    [Test] 
    public void AddWhenCallingAddsObjectToDatabase() 
    { 
     IBaseRepository<T> repository = GetRepository(); 
     T entity = GetTestEntity(); 

     repository.Add(entity); 
    } 
} 

Ahora, para cada objeto de dominio que tendría que poner en práctica cómo para inicializar el Repositorio y cómo crear una entidad de prueba, que parece justo, dado que serían diferentes ...

Todo lo que tengo que hacer ahora es escribir el accesorio de prueba real ¿no? De esta manera:

[TestFixture] 
public class FooRepositoryTests: BaseRepositoryTests<Foo> 
{ 
    public override IBaseRepository<Foo> GetRepository() 
    { 
     throw new NotImplementedException(); 
    } 

    public override Foo GetTestEntity() 
    { 
     throw new NotImplementedException(); 
    } 
} 

Esto debería conseguirme comenzado y dame una prueba fallida ya que el tiro lo romperá (i también trató la aplicación real de los métodos sin suerte). Pero los testrunners (probaron la correlación de prueba de ambos nunits GUI y resharpers) simplemente ignoran mi prueba base. Se muestra y todo, pero se informa como Ignorado.

así que hice un poco de cavar ... NUnit tiene esta propiedad en la TextFixtureAttribute que le permite especificar qué tipo de que se está probando así que he intentado poner el atributo

[TestFixture(typeof(Foo))] 

En primer lugar la base y también la versión Foo. Cuando lo pongo en la versión de Foo, simplemente ignora la prueba de la base, y cuando lo pongo en la base ... bueno, se vuelve rojo porque los métodos arrojan excepciones, lo que sería bueno, excepto que incluso cuando realizo la implementación real en FooTests, todavía no funcionan (obviamente, la prueba Base, dado el atributo TestFixture, nunca sabría qué clases heredan de él, entonces, ¿cómo sabría encontrar la implementación).

Entonces, ¿qué tengo que hacer? Podría hacer que la prueba en la clase de prueba base sea virtual y luego anularla en FooBaseRepositoryTests, solo para llamar a la implementación desde la base, que es una solución coja, creo ...

¿Qué más hay que hacer? ¿Me estoy perdiendo de algo? Por favor ayuda, alguien ... :)

Respuesta

1

Cuando utiliza el atributo [TestFixture(typeof(Foo))] en la clase de dispositivo para utilizarlo para diferentes tipos; no se supone que sea abstracto

Si se usa en el dispositivo Foo, esa clase debe ser genérica y no debe escribirse para Foo.

A partir de los documentos:

[TestFixture] 
public class AbstractFixtureBase 
{ 
    ... 
} 

[TestFixture(typeof(string))] 
public class DerivedFixture<T> : AbstractFixtureBase 
{ 
    ... 
} 

http://www.nunit.org/index.php?p=testFixture&r=2.5.5

+0

Veo tu punto, gracias :) Sin embargo, no resuelve mi problema, ya que el AbstractFixtureBase ganó ' ser capaz de tener la lógica para "AddWhenCallingAddsObjectToDatabase()", lo que me hace escribir casi la misma implementación para todos los dispositivos derivados ... –

+0

Estoy marcando tu respuesta como la correcta. Supongo que no es posible con NUnit, así que esto realmente me muestra cómo funciona la API. –

0

No he probado tu ejemplo pero podrías intentarlo si colocas los atributos TestFixture y Test en la misma clase. Intenta también ponerlo en la clase base.

+0

Probé muchas combinaciones de TestFixture y Test en ambas clases, honestamente creo que intenté con todas;) –

2

tuve este problema recientemente y encontró una solución diferente.Tengo una interfaz IRepository genérico que quiero ser capaz de probar con varias implementaciones, así que creé una clase base que ignora sí durante la instalación, pero este comportamiento se anula por sus descendientes:

[TestFixture] 
public class AbstractRepositoryTests 
{ 
    protected IRepository _repository; 

    [SetUp] 
    public virtual void SetUp() 
    { 
     Assert.Ignore(); 
    } 

    [Test] 
    public void AddToRepository() 
    { 
     // Place logic using _repository here 
    } 
} 

entonces anulan la el comportamiento de instalación en mi descendiente crear una instancia de un objeto de depósito en lugar de ignorar todas las pruebas:

public class InMemoryRepositoryTests : AbstractRepositoryTests 
{ 
    [SetUp] 
    public override void SetUp() 
    { 
     _repository = new InMemoryRepository<string>(); 
    } 
} 

La clase derivada se ejecutará la totalidad de sus padres pruebas correctamente. La única parte ligeramente desordenada sobre esto es que la clase base crea un montón de pruebas "Ignoradas", que no son muy claras.

+5

Hará su vida más fácil si realmente crea AbstractRepositoryTests como una clase abstracta. Entonces solo se crearán instancias de sus implementaciones, y no tendrá el problema de que la clase base cree una serie de pruebas ignoradas. – kiprainey

Cuestiones relacionadas