How to compile Entity 6 Async Projecting Query infrastructure

Using Testing with asynchronous queries in the article Testing with the Mocking Framework on MSDN , I was able to create many successful tests.

Here is my test code that NSubstitute uses for mocks:

var dummyQueryable = locations.AsQueryable(); var mock = Substitute.For<DbSet<Location>, IDbAsyncEnumerable<Location>, IQueryable<Location>>(); ((IDbAsyncEnumerable<Location>)mock).GetAsyncEnumerator().Returns(new TestDbAsyncEnumerator<Location>(dummyQueryable.GetEnumerator())); ((IQueryable<Location>)mock).Provider.Returns(new TestDbAsyncQueryProvider<Location>(dummyQueryable.Provider)); ((IQueryable<Location>)mock).Expression.Returns(dummyQueryable.Expression); ((IQueryable<Location>)mock).ElementType.Returns(dummyQueryable.ElementType); ((IQueryable<Location>)mock).GetEnumerator().Returns(dummyQueryable.GetEnumerator()); sut.DataContext.Locations = mock; var result = await sut.Index(); result.Should().BeView(); 

sut.Index() does not do much, but it makes the following request:

 await DataContext.Locations .GroupBy(l => l.Area) .ToListAsync()); 

This works fine until I add a projection to the query:

 await DataContext.Locations .GroupBy(l => l.Area) .Select(l => new LocationsIndexVM{ Area = l.Key }) // added projection .ToListAsync()); 

which leads to this exception:

 System.InvalidOperationException The source IQueryable doesn't implement IDbAsyncEnumerable<LocationsIndexVM>. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068. at System.Data.Entity.QueryableExtensions.AsDbAsyncEnumerable(IQueryable`1 source) at System.Data.Entity.QueryableExtensions.ToListAsync(IQueryable`1 source) at Example.Web.Controllers.HomeController.<Index>d__0.MoveNext() in HomeController.cs: line 25 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at Example.Test.Web.Controllers.HomeControllerShould.<TempTest>d__4.MoveNext() in HomeControllerShould.cs: line 71 

UPDATE I downloaded a small, simple solution that reproduces this problem.

Can someone provide an example of what is required for a unit test query, which is like async , and contains a projection .Select() ?

+6
source share
1 answer

So, I did a little work, and the problem is with how TestDbAsyncEnumerable<T> provides IQueryProvider . My best guess about the reasoning below, and a solution below that.

TestDbAsyncEnumerable<T> inherits from EnumerableQuery<T> , which in turn inherits from IQueryable<T> and explicitly implements the Provider property of this interface:

 IQueryProvider IQueryable.Provider { get ... } 

Given that it is implemented explicitly, I assume that the internal LINQ elements explicitly set the type before trying to get the Provider :

 ((IQueryable<T>)source).Provider.CreateQuery(...); 

I don't have a source (and don't worry), but I believe that type binding rules differ for explicit implementations; essentially, the Provider property on your TestDbAsyncEnumerable<T> not considered an implementation of IQueryable<T>.Provider , since the explicit exists further down the chain, so your TestDbAsyncQueryProvider<T> never returns.

The fix for this is to make TestDbAsyncEnumerable<T> also inherit IQueryable<T> and explicitly implement the Provider property as shown below (corrected using article

+15
source

All Articles