views:

117

answers:

1

Is it possible to Mock a Linq Expression via Moq using a Generic class such as ~1Repository. ~IRepository being something that is injected via an IoC such as StructureMap or Windsor?

CODE TO TEST:

   var person = _repository.Find<Person>()
                           .Where(p => p.Id == person.Id).SingleOrDefault();

TEST:

    var repository = new Mock<IRepository>();

    repository.Setup(i => i.Find<Person>()
                     .Where(p => p.Id == person.Id).SingleOrDefault())
                     .Returns(person).Verifiable();

EXCEPTION:

System.ArgumentException: Invalid setup on a non-member method:i => i.Find().Where(p => p.Id == "Fred").SingleOrDefault()

SOLUTION

    using System.Linq;
    ...

    _container.GetMock<IRepository>.Setup(i => i.Find<Person>())
                     .Returns(new List{person}.AsQueryable()).Verifiable();

    ...
+3  A: 

If Find<T>() is an extension method on IRepository, then I don't think it'll work, because you're dealing with a static type.

If Find<T>() is a method on IRepository, then you set up a return value only for repository.Find<Person>().

Create an IEnumerable<> or IQueryable<> for Find<>() to return (whichever type it is actually supposed to return -- I don't know which it is), and the LINQ expression will just do its work on that in the actual class. You don't have to mock the LINQ because that is just filtering the results of your own method, even though in production, if this is, say, Entity Framework or LINQ to SQL, the whole expression will instead be converted to an optimized database call.

If in your setup you give the collection an item with a matching ID, you'll assert that you get it back.
If in your setup you don't give the collection an item with a matching ID, you'll assert that you get null (the default).
If in your setup you return null from repository.Find<>(), you'll assert than an exception is thrown because you can't call the extension methods on null.

Jay
Thank you so much, this worked like a charm.
Andrew