Entity framework 如何模拟实体框架6异步投影查询

Entity framework 如何模拟实体框架6异步投影查询,entity-framework,mocking,entity-framework-6,Entity Framework,Mocking,Entity Framework 6,通过利用,我已经能够创建许多成功通过的测试 以下是我的测试代码,用于模拟: var dummyQueryable = locations.AsQueryable(); var mock = Substitute.For<DbSet<Location>, IDbAsyncEnumerable<Location>, IQueryable<Location>>(); ((IDbAsyncEnumerable<Location>)mock).

通过利用,我已经能够创建许多成功通过的测试

以下是我的测试代码,用于模拟:

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();
在我将投影添加到查询中之前,这一切都很正常:

await DataContext.Locations
    .GroupBy(l => l.Area)
    .Select(l => new LocationsIndexVM{ Area = l.Key }) // added projection
    .ToListAsync());
这导致了这种例外情况:

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
更新:我发现它重现了这个问题


任何人都可以提供一个例子,说明对一个既异步又包含.Select投影的查询进行单元测试需要什么?

所以我做了一些挖掘,问题在于TestDbAsyncEnumerable公开IQueryProvider的方式。下面是我对推理的最佳猜测,下面是解决方案

TestDbAsyncEnumerable继承自EnumerableQuery,EnumerableQuery又继承自IQueryable,并显式实现此接口的Provider属性:

IQueryProvider IQueryable.Provider { get ... }
考虑到它是显式实现的,我假设LINQ内部在尝试获取提供程序之前显式地强制转换类型:

IQueryProvider IQueryable.Provider { get ... }
((IQueryable<T>)source).Provider.CreateQuery(...);
public class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
    public TestDbAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable)
    { }

    public TestDbAsyncEnumerable(Expression expression) : base(expression)
    { }

    public IDbAsyncEnumerator<T> GetAsyncEnumerator()
    {
        return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
    }

    IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
    {
        return GetAsyncEnumerator();
    }

    IQueryProvider IQueryable.Provider
    {
        get { return new TestDbAsyncQueryProvider<T>(this); }
    }
}