2016-09-27 10 views
5

私はドットネットコアアプリケーションでテストするためにXUNITを使用しています。EntityFrameworkCoreのIDbAsyncQueryProvider

私のdatacontextのDbSetで非同期クエリを内部的に作成しているサービスをテストする必要があります。

I've seen here DbSetを非同期で嘲笑することが可能です。

私が抱えている問題は、IDbAsyncQueryProviderが、私が使用しているEntityframeworkCoreで利用できないようです。

ここに間違いがありますか?他の誰かがこの作業をしていますか?

はGitHubの上で尋ねた後

EDIT

(うまくいけば、私は単純な何かが欠けている、長い一日関係者)、私はこのクラスにポイントを得た: 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); } 
     } 
    } 
} 

私は今、これを実装しようとした、具体的にこれらの2つの方法の周りにいくつかのより多くの問題の中に実行した:私は誰かが私がやっているのと正しい方向に私を指すことができることを願っています

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

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

違う。

+0

新しい問題はありますか?新しい問題を質問(およびタイトル)に追加する必要があります。 –

+0

あなたはこれに対する解決策を見つけましたか? – Dan

+0

@ダン私は解決策なしで動いてしまった。 – Chris

答えて

5

私はついにこれを動作させました。

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のそれらのテスト実装をクリーンアップすることができるかもしれません:彼らは少しので、次のコードは、私のために働いたIAsyncEnumerableIDbAsyncEnumerableからEntityFrameworkCoreにインタフェースを変更しました。私は試していない、私はちょうどそれを働かせた。

はあなたのあなたのDbContextニーズにDbSetvirtualとしてマークすることを忘れないでくださいまたは他のあなたは正しく、この作業をするためにDbContext比べていくつかのインターフェイスのラッパーを実装する必要があります。