I have created the following extension method for an IQueryable
to use it in Entity Framework DbContext moqs in unit tests
public static DbSet<T> BuildMockDbSet<T>(this IQueryable<T> source)
where T : class
{
var mock = new Mock<DbSet<T>>();
var sourceList = source.ToList();
mock.As<IDbAsyncEnumerable<T>>()
.Setup(x => x.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<T>(sourceList.GetEnumerator()));
mock.As<IQueryable<T>>()
.Setup(x => x.Provider)
.Returns(new TestDbAsyncQueryProvider<T>(source.Provider));
mock.As<IQueryable<T>>()
.Setup(x => x.Expression)
.Returns(source.Expression);
mock.As<IQueryable<T>>()
.Setup(x => x.ElementType)
.Returns(source.ElementType);
mock.As<IQueryable<T>>()
.Setup(x => x.GetEnumerator())
.Returns(sourceList.GetEnumerator());
mock.Setup(s => s.AsNoTracking()).Returns(mock.Object);
mock.Setup(x => x.Include(It.IsAny<string>())).Returns(mock.Object);
mock.Setup(x => x.FirstOrDefault(It.IsAny<Expression<Func<T,bool>>>())).Returns((Expression<Func<T,bool>> x) => sourceList.FirstOrDefault(x as Func<T,bool>));
mock.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) =>
{
sourceList.Add(s);
}).Returns((T v) => v);
return mock.Object;
}
The problem I am experiencing is that when I add a new item to it, i am adding it in fact to sourceList
which is not the same object as source
. So looping over the items should return the items of the sourceList
.
For the FirstOrDefault
method, this does not work however. I would like to simply get whatever predicate was given originally and pass that to the FirstOrDefault
method of the sourceList
. But I am unable to set this up correctly.
The exception message is only saying that what I do is invalid, not why nor how it should be.