42 votes

Classes moqueuses qui implémentent IQueryable avec Moq

J'ai passé une soirée à essayer de se moquer d'un objet qui implémente IQueryable :

 public interface IRepo<T> : IQueryable<T>
{
}

Le mieux que j'ai pu trouver est quelque chose comme ça :

 var items = new Item[] {}.AsQueryable();

var repo = new Mock<IRepo>();
repo.Setup(r => r.GetEnumerator()).Returns(items.GetEnumerator());
repo.Setup(r => r.Provider).Returns(items.Provider);
repo.Setup(r => r.ElementType).Returns(items.ElementType);
repo.Setup(r => r.Expression).Returns(items.Expression);

Existe-t-il une façon plus concise de faire la même chose ? Il serait plus facile d'exposer une propriété/méthode dans IRepo qui renvoie IQueryable et le simulacre simplement comme ceci :

 repo.Setup(r => r.GetItems()).Returns(new Items[]{ }.AsQueryable());

Mais ce n'est pas ce que je veux faire =)

8voto

Rob Points 53

La réponse de Rune est géniale et m'a fait gagner du temps pour trouver comment faire de même. Le petit problème est que si vous appelez deux fois des méthodes d'extension IQueryable sur votre IQueryable (par exemple, ToList()), la deuxième fois, vous n'obtiendrez aucun résultat. C'est parce que l'énumérateur est à la fin et doit être réinitialisé. À l'aide de Rhinomocks, j'ai modifié l'implémentation de GetEnumerator pour :

 mock.Stub(r => r.GetEnumerator()).Do((Func<IEnumerator<T>>) (() => { 
    var enumerator = queryable.GetEnumerator();
    enumerator.Reset();
    return enumerator;
}));

J'espère que ça fera gagner du temps à quelqu'un.

6voto

Mark Good Points 1956

J'aime la réponse de Rune. Voici une version générique IQueryable :

 public static void SetupIQueryable<TRepository, TEntity>(this Mock<TRepository> mock, IQueryable<TEntity> queryable)
   where TRepository : class, IQueryable<TEntity>
{
    mock.Setup(r => r.GetEnumerator()).Returns(queryable.GetEnumerator());
    mock.Setup(r => r.Provider).Returns(queryable.Provider);
    mock.Setup(r => r.ElementType).Returns(queryable.ElementType);
    mock.Setup(r => r.Expression).Returns(queryable.Expression);
}

2voto

dahlbyk Points 24897

Je pense que c'est à peu près le mieux que vous puissiez faire avec Moq. Je pense qu'une option plus lisible serait de lancer votre propre FakeRepo<T> qui dérive de System.Linq.EnumerableQuery<T> :

 public class FakeRepo<T> : EnumerableQuery<T>, IRepo<T>
{
    public FakeRepo(IEnumerable<T> items) : base(items) { }
}

Mise à jour : vous pourrez peut-être y parvenir en vous moquant de EnumerableQuery<T> puis en utilisant As<T>() :

 var items = new Item[0];

var repo = new Mock<EnumerableQuery<Item>(items).As<IRepo>();

0voto

akekir Points 505

J'ai eu le même problème. Je l'ai corrigé en changeant cette ligne

 mock.Setup(r => r.GetEnumerator()).Returns(queryable.GetEnumerator());

à

 mock.Setup(r => r.GetEnumerator()).Returns(queryable.GetEnumerator);

J'espère que des commentaires supplémentaires ne sont pas nécessaires ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X