2016-09-27 130 views
5

我使用XUNIT在点网络核心应用程序中进行测试。EntityFrameworkCore中的IDbAsyncQueryProvider

我需要测试一个内部在我的datacontext中对DbSet进行异步查询的服务。

I've seen here嘲笑DbSet异步是可能的。

我遇到的问题是IDbAsyncQueryProvider似乎不在我使用的EntityframeworkCore中。

我不正确吗?有没有其他人得到这个工作?

(漫长的一天,希望我只是失去了一些东西简单)

编辑

问GitHub上后,我点到这个类: https://github.com/aspnet/EntityFramework/blob/dev/src/Microsoft.EntityFrameworkCore/Query/Internal/IAsyncQueryProvider.cs

这是到目前为止,我试图实现这一点:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Threading; 
using System.Threading.Tasks; 
using Microsoft.EntityFrameworkCore.Query.Internal; 

namespace EFCoreTestQueryProvider 
{ 
    internal class TestAsyncQueryProvider<TEntity>: IAsyncQueryProvider 
    { 
     private readonly IQueryProvider _inner; 

     internal TestAsyncQueryProvider(IQueryProvider inner) 
     { 
      _inner = inner; 
     } 

     IQueryable CreateQuery(Expression expression) 
     { 
      return new TestDbAsyncEnumerable<TEntity>(expression); 
     } 

     IQueryable<TElement> CreateQuery<TElement>(Expression expression) 
     { 
      return new TestDbAsyncEnumerable<TElement>(expression); 
     } 

     object Execute(Expression expression) 
     { 
      return _inner.Execute(expression); 
     } 

     TResult Execute<TResult>(Expression expression) 
     { 
      return _inner.Execute<TResult>(expression); 
     } 

     IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression) 
     { 
      return Task.FromResult(Execute<TResult>(expression)).ToAsyncEnumerable(); 
     } 

     Task<TResult> IAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) 
     { 
      return Task.FromResult(Execute<TResult>(expression)); 
     } 
    } 

    internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, System.Collections.Generic.IAsyncEnumerable<T>, IQueryable<T> 
    { 
     public TestDbAsyncEnumerable(IEnumerable<T> enumerable) 
      : base(enumerable) 
     { } 

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

     public IAsyncEnumerator<T> GetAsyncEnumerator() 
     { 
      return new TestDbAsyncEnumerable<T>(this.AsEnumerable()).ToAsyncEnumerable(); 
     } 

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

     IAsyncEnumerator<T> IAsyncEnumerable<T>.GetEnumerator() 
     { 
      throw new NotImplementedException(); 
     } 

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

我现在想实现这一点,并遇到了一些问题,特别是围绕这两种方法:

public IAsyncEnumerator<T> GetAsyncEnumerator() 
{ 
    return new TestDbAsyncEnumerable<T>(this.AsEnumerable()).ToAsyncEnumerable(); 
} 

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

我希望有人可以点我在正确的方向,以我在做什么错误。

+0

你碰到什么新问题?应该将新问题添加到问题(和标题)中。 –

+0

您是否找到解决方案? – Dan

+0

@丹我最终没有找到解决方案。 – Chris

回答

5

我终于得到了这个工作。他们稍微改变接口的EntityFrameworkCore从IDbAsyncEnumerableIAsyncEnumerable所以下面的代码为我工作:

public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T> 
{ 
    public AsyncEnumerable(Expression expression) 
     : base(expression) { } 

    public IAsyncEnumerator<T> GetEnumerator() => 
     new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator()); 
} 

public class AsyncEnumerator<T> : IAsyncEnumerator<T> 
{ 
    private readonly IEnumerator<T> enumerator; 

    public AsyncEnumerator(IEnumerator<T> enumerator) => 
     this.enumerator = enumerator ?? throw new ArgumentNullException(); 

    public T Current => enumerator.Current; 

    public void Dispose() { } 

    public Task<bool> MoveNext(CancellationToken cancellationToken) => 
     Task.FromResult(enumerator.MoveNext()); 
} 

[Fact] 
public async Task TestEFCore() 
{ 
    var data = 
     new List<Entity>() 
     { 
      new Entity(), 
      new Entity(), 
      new Entity() 
     }.AsQueryable(); 

    var mockDbSet = new Mock<DbSet<Entity>>(); 

    mockDbSet.As<IAsyncEnumerable<Entity>>() 
     .Setup(d => d.GetEnumerator()) 
     .Returns(new AsyncEnumerator<Entity>(data.GetEnumerator())); 

    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.Provider).Returns(data.Provider); 
    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.Expression).Returns(data.Expression); 
    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.ElementType).Returns(data.ElementType); 
    mockDbSet.As<IQueryable<Entity>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator()); 

    var mockCtx = new Mock<SomeDbContext>(); 
    mockCtx.SetupGet(c => c.Entities).Returns(mockDbSet.Object); 

    var entities = await mockCtx.Object.Entities.ToListAsync(); 

    Assert.NotNull(entities); 
    Assert.Equal(3, entities.Count()); 
} 

你也许能够清理AsyncEnumerableAsyncEnumerator这些测试实现,甚至更多。我没有尝试,我只是把它工作。

记住你DbSetDbContext需要被标记为virtual,否则你将需要实现在DbContext一些接口封装,使这项工作正常。

相关问题