0

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.

enter image description here

The exception message is only saying that what I do is invalid, not why nor how it should be.

10
  • 1
    Maybe try MockQueryable Commented Jan 20 at 15:26
  • 3
    Then you can at least get yourself "inspired" by what they do. Commented Jan 20 at 15:35
  • 1
    Anyhow, the problem is that methods like FirstOrDefault are implemented as extension methods which are notoriously "hard" to mock. "Hard" meaning: it's not supported by mocking frameworks. Commented Jan 20 at 15:40
  • 1
    Thanks for the recommendations, but our project cannot even handle that package since we are still working in .net Framework which is not compatible. Best I can do I believe is being "inspired" by their code which will require adjustments because of this .net difference Commented Jan 21 at 8:08
  • 1
    @WouterVandenputte You are setting up the GetEnumerator() incorrectly by providing an instance. Use a delegate. Reference: stackoverflow.com/a/43998703/5233410 . I would also suggest casting the source if possible instead of trying to maintain separate lists/collections Commented Jan 21 at 13:57

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.