2010-02-11 4 views
30

Je crée un référentiel qui expose IQueryable. Quelle est la meilleure façon de se moquer de cela pour mes tests unitaires?Comment puis-je simuler IQueryable <T>

Depuis que je suis en utilisant RhinoMocks pour le reste de mes objets fantaisie, j'ai essayé de faire ce qui suit:

IQueryable<MyObject> QueryObject = 
    MockRepository.GenerateStub<IQueryable<MyObject>>(); 

Cela ne fonctionne pas si j'ai essayé ce faisant ceci:

IQueryable<MyObject> QueryObject = 
    (new List<MyObject> { new MyObject() }).AsQueryable(); 

Y a-t-il un meilleur moyen de le faire, ou est-ce que d'autres frameworks moqueurs ont construit le support pour IQueryable?

mon interface référentiel ressemble à ceci:

public interface IRepository<T> where T : TableServiceEntity 
{ 
    IQueryable<T> Table { get; } 
    void Attach(T existingItem); 
    void Delete(T itemToDelete); 
    void Insert(T newItem); 
    T Load(string partitionKey, string rowKey); 
    IEnumerable<T> Load(string partitionKey); 
    IEnumerable<T> Query(IQueryable<T> query); 
    IEnumerable<T> Last(int count); 
    T Last(); 
    void Update(T item); 
} 

Voici la méthode que je veux tester:

public Post LoadPost(int year, int month, int day, string slug) 
{ 
    var query = from p in _blogRepository.Table 
       where 
        p.PartitionKey == Key.Partition(year, month, day) 
        && p.Slug == slug 
       select p; 

    var posts = _blogRepository.Query(query.Take(1)); 

    return posts.First(); 
} 

Ensuite, voici le test que je l'ai en ce moment qui va tester LoadPost .

[Fact] 
public void LoadWillRetrieveByPartitionKeyAndRowKeyWhenUsingUriFormat() 
{ 
    Repository 
     .Stub(x => x.Query(Arg<IQueryable<Post>>.Is.Anything)) 
     .Return(new List<Post> {_post}); 

    var result = Service.LoadPost(
          _post.Year(), 
          _post.Month(), 
          _post.Day(), 
          _post.Slug); 

    Assert.NotNull(result); 
} 

Le code est tiré de mon projet AzureBlog.

+0

Pouvez-vous coller votre test? – Grzenio

Répondre

8

que je fais habituellement exactement ce que vous avez fini par faire dans votre test. Lorsque j'écris mes tests, je suppose que les classes de bibliothèques .Net fonctionnent correctement et ne contiennent pas de bugs, donc je peux les utiliser dans les tests. Quand j'ai besoin d'une liste de test, d'une collection, d'un queryable, d'un dictionnaire, etc., je crée juste la chose réelle et je la remplis avec des données de test. Cela rend les tests beaucoup plus lisibles et plus rapides à écrire, et pour être honnête, le risque est inexistant.

3

Si vous voulez simuler votre référentiel, vous ne vous moquerez pas de IQueryable. Au lieu de cela, simulez les méthodes de votre référentiel pour renvoyer des valeurs fixes et connues (comme votre deuxième exemple) qui peuvent être utilisées pour exécuter vos tests unitaires.

+0

J'avais commencé cette route et j'ai fini par créer une couche supplémentaire d'un dépôt spécifique sur un dépôt générique. Cela a abouti à mon service de domaine -> Domain Repository -> Référentiel générique. Si je suis capable de passer de Domain Service -> Generic Repository et être encore testable sans que les détails d'implémentation ne fuient dans le Domain Service, je serais beaucoup plus heureux car c'est moins de code qui doit être maintenu et testé. –

+0

Je vois ce que vous dites. Mais si votre question provient de l'écriture de tests unitaires pour votre DomainService, alors je pense que vous devriez vous moquer du DomainRepository et ne vous inquiétez pas du Référentiel générique (pour l'instant). L'unité testant DomainService est mieux accomplie en se moquant de ses dépendances. En ce qui concerne DomainService, il ne devrait pas se soucier de la façon dont DomainRepository est implémenté (c'est-à-dire héritant d'une classe de base). J'espère que cela t'aides! – PatrickSteele

0

Je ne sais pas si cela va vous aider ... mais j'ai fait quelque chose comme ce dont vous parlez. Dans mon scénario, j'avais une classe de contexte de données qui utilisait le référentiel.

J'ai commencé par créer une interface (IRepository) qui incluait la méthode IQueryable. Ensuite, j'ai créé deux classes qui implémentent cette interface. Une classe utilise un ORM pour la manipulation de données (DbEntityRepository) et une autre classe utilise une propriété de classe (MemoryRepository). La classe de contexte de données avait un constructeur qui nécessitait l'IRepository. Pour ce faire, je pourrais utiliser le MemoryRepository lors du test du contexte de données et je pourrais utiliser le DbEntityRepository pour l'application.

Si vous êtes intéressé ... vous pouvez trouver le code sur CodePlex: IQToolkitContrib

2

Je sais que c'est une vieille question, mais je veux juste ajouter mes 2 cents.

J'ai eu le même problème avec les référentiels générés avec SharpLite, qui est un framework ASP.NET MVC que j'utilise de temps en temps. Après un certain temps, j'ai trouvé une solution, le seul problème est d'utiliser Moq, et non Rhino Mocks, mais peut-être que vous pouvez trouver un moyen de l'adapter. J'ai fait un blog post here sur la façon de le faire.

Il s'agit essentiellement de créer une liste qui implémente IQueryable et l'utilise comme un faux fond de données. J'espère que je peux aider!

Questions connexes