2010-08-31 15 views
11

Donc, fondamentalement, j'ai un objet domaine et un référentiel générique qui peut faire des opérations CRUD avec cet objet.Comment puis-je créer un BaseTest générique avec NUnit dont je peux hériter et avoir des tests de base?

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

J'ai donc plusieurs implémentations de cette interface, une pour chaque objet de domaine.

Je voudrais écrire quelques tests d'intégration (en utilisant nunit) et que je pensais que je ferais un BaseRepositoryTest - comme ceci:

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

Maintenant, pour chaque objet de domaine je dois mettre en œuvre comment pour initialiser le Repository et comment créer une entité de test, ce qui semble juste, étant donné qu'ils seraient différents ...

Tout ce que j'ai à faire maintenant est d'écrire l'appareil de test proprement dit? Comme ceci:

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

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

Cela devrait me commencer et me donner un test a échoué car le jet va casser (je l'ai essayé aussi mettre en œuvre effectivement les méthodes sans chance). Mais les testeurs (essayé à la fois l'interface graphique de nunits et le testeur de resharpers) ignorent simplement mon test de base! Il apparaît et tout - mais rapporté comme ignoré.

donc je l'ai fait un peu de creuser ... NUnit ont cette propriété sur le TextFixtureAttribute qui vous permet de spécifier quel type de vous testez donc j'essayé de mettre l'attribut

[TestFixture(typeof(Foo))] 

Sur la base de la première et aussi la version Foo. Quand on le met sur la version Foo, il ignore encore le test de la base, et quand je le mets sur la base ... il devient rouge car les méthodes lancent des exceptions, ce qui serait bien sauf que même quand je fais l'implémentation dans FooTests, ils ne fonctionneront toujours pas (évidemment, le test de base étant donné que l'attribut TestFixture ne connaitrait jamais les classes qui en héritent, alors comment savoir s'il trouve l'implémentation).

Alors qu'est-ce que je suis coincé à faire? Je pourrais faire le test dans la classe de test de base virtuelle, puis le remplacer dans FooBaseRepositoryTests, seulement pour appeler l'implémentation de base, ce qui est une solution boiteuse je pense ...

Quoi d'autre à faire? Est-ce que je manque quelque chose? S'il vous plaît aider, quelqu'un ... :)

Répondre

1

Lorsque vous utilisez l'attribut [TestFixture(typeof(Foo))] sur la classe d'appareils afin de l'utiliser pour différents types; Ce n'est pas censé être abstrait.

Si elle est utilisée sur l'appareil Foo, cette classe doit être générique et non typée pour Foo.

De la documentation:

[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

Je vois votre point, merci :) Cela ne résout pas mon problème, car AbstractFixtureBase a gagné ' t être en mesure d'avoir la logique pour "AddWhenCallingAddsObjectToDatabase()", ce qui me fait écrire la même mise en œuvre pour tous les appareils dérivés ... –

+0

Je signale votre réponse comme correcte. Je suppose que ce n'est pas possible avec NUnit, donc cela me montre comment fonctionne l'API. –

0

Je n'ai pas essayé votre exemple mais vous pourriez essayer si vous mettez les attributs TestFixture et Test dans la même classe. Essayez aussi de le mettre dans la classe de base.

+0

J'ai essayé beaucoup de combinaisons de TestFixture et Test sur les deux classes, je pense honnêtement que je les ai toutes essayées;) –

2

J'ai eu cette question récemment et trouvé une solution différente.J'ai une interface IRepository générique que je veux être en mesure de tester avec de multiples implémentations, donc je créé une classe de base qui se tient pas compte lors de l'installation, mais ce comportement est surchargée par ses descendants:

[TestFixture] 
public class AbstractRepositoryTests 
{ 
    protected IRepository _repository; 

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

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

je puis remplacer les comportement d'installation dans mon descendant pour instancier un objet référentiel plutôt que d'ignorer tous les tests:

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

La classe dérivée se déroulera tous ses tests de parents correctement. La seule partie un peu désordonnée à ce sujet est que la classe de base crée un tas de tests "ignorés", ce qui n'est pas très propre.

+5

Vous allez vous rendre la vie plus facile si vous créez réellement AbstractRepositoryTests en tant que classe abstraite. Alors seulement ses implémentations seront instanciées, et vous n'aurez pas le problème de la classe de base créant un tas de tests ignorés. – kiprainey