Reputation: 9662
I have query expression in my code that does the following:
repository.Context.AsQueryable<Option>().Where(o => o.Id == id && o.Name == "Something").Select(o => o.Id).ToArray();
How am I going to create a Stub for the above code? It seems like a lot of work. Is there anyway where I can simply ignore what is passed to the Where and Select methods and then return whatever I want to return?
I don't really care about what is passed in the Where and Select method. I just want to return my hard coded list of items in the end.
Upvotes: 3
Views: 182
Reputation: 12632
As an option, use your code as a dependency. This way you can stub it without touching context at all. For example:
public class OptionService : IOptionService
{
private IRepository _repository;
public OptionService(IRepository repository)
{
_repository = repository;
}
public int[] GetOptionsWithName(int id, string name)
{
_repository.Context.AsQueryable<Option>()
.Where(o => o.Id == id && o.Name == name)
.Select(o => o.Id)
.ToArray();
}
}
public interface IOptionService
{
int[] GetOptionsWithName(int id, string name);
}
Inject IOptionService
into your code with logic similar, how IRepository
is injected into the OptionService
, and stub the method GetOptionsWithName
in the test to return whatever you want.
Upvotes: 2
Reputation: 156624
The short answer is: No, because .Where() and .Select() are extension methods, which cannot be mocked.
The longer answer is: Yes, because .Where()
and .Select()
on IQueryable<>
s do nothing but indicate to the underlying query provider that they were just called. So you could technically create a stub for the query provider and look at what happened to it before it got evaluated.
But the easy answer is: I've found the best approach is to use an actual in-memory representation that is capable of acting like a queryable, like a List. Then, rather than trying to validate the lambda expressions themselves, test the resulting data.
var options = new[] {new Option(...)};
repositoryMock.Setup(r => r.Context).Returns(contextMock.Object);
contextMock.Setup(c => c.AsQueryable<Option>()).Returns(options.AsQueryable());
...
Assert.AreEqual(results[0], options[0].Id);
The downside to this is that there's no way to test that your method only uses expressions that can be translated by your query provider. But I generally find this is "good enough" for unit-testing purposes.
Upvotes: 1